Initial commit
Change-Id: I6a4444e3c193dae437cd7929f4c39aba7b749efa
diff --git a/include/freeDiameter/CMakeLists.txt b/include/freeDiameter/CMakeLists.txt
new file mode 100644
index 0000000..4db3293
--- /dev/null
+++ b/include/freeDiameter/CMakeLists.txt
@@ -0,0 +1,249 @@
+#CMake configuration for freeDiameter include directory
+
+Project("freeDiameter includes directory" C)
+
+########################
+# Configurable parameters
+
+# Disable SCTP support completely ?
+OPTION(DISABLE_SCTP "Disable SCTP support?" OFF)
+IF (NOT DISABLE_SCTP)
+ OPTION(DEBUG_SCTP "Verbose SCTP (for debug)?" OFF)
+ OPTION(SCTP_USE_MAPPED_ADDRESSES "Use v6-mapped v4 addresses in SCTP (workaround some SCTP limitations)?" OFF)
+ENDIF (NOT DISABLE_SCTP)
+
+# Find TODO items in the code easily ?
+OPTION(ERRORS_ON_TODO "(development) Generate compilation errors on TODO items ?" OFF)
+
+# In DEBUG mode, each log can contain pid, calling function and file for easy debug. Set to ON to display this information.
+OPTION(DEBUG_WITH_META "Show calling location in logs?" OFF)
+
+# Create the absolute path for searching extensions
+SET(DEFAULT_EXTENSIONS_PATH ${CMAKE_INSTALL_PREFIX}/${INSTALL_EXTENSIONS_SUFFIX})
+
+# IDNA considerations
+OPTION(DIAMID_IDNA_IGNORE "Ignore completely invalid characters in Diameter Identities (process blindly)?" OFF)
+IF (NOT DIAMID_IDNA_IGNORE)
+ OPTION (DIAMID_IDNA_REJECT "Reject internationalized Diameter Identities, do not attempt to convert it (stringprep) ?" OFF)
+ENDIF (NOT DIAMID_IDNA_IGNORE)
+
+# Disable expiration of connections with dynamically connected peers as per RFC 3539 ? (default is enabled)
+# Note: if someone needs, we could also make the delay configurable here...
+OPTION(DISABLE_PEER_EXPIRY "Disable RFC3539 Peers Connections Expiration after inactivity?" OFF)
+
+# The following workaround increases compatibility with some implementations without breaking anything in freeDiameter,
+# so it can be enabled without risk. We keep it disabled by default anyway for those people who use freeDiameter to check the
+# compliancy of their implementation with the Diameter RFC...
+OPTION(WORKAROUND_ACCEPT_INVALID_VSAI "Do not reject a CER/CEA with a Vendor-Specific-Application-Id AVP containing both Auth- and Acct- application AVPs?" OFF)
+
+MARK_AS_ADVANCED(DISABLE_SCTP DEBUG_SCTP SCTP_USE_MAPPED_ADDRESSES ERRORS_ON_TODO DEBUG_WITH_META DIAMID_IDNA_IGNORE DIAMID_IDNA_REJECT DISABLE_PEER_EXPIRY WORKAROUND_ACCEPT_INVALID_VSAI)
+
+########################
+### System checks part
+
+INCLUDE (CheckLibraryExists)
+INCLUDE (CheckFunctionExists)
+INCLUDE (CheckIncludeFiles)
+INCLUDE (CheckSymbolExists)
+INCLUDE (CheckCSourceCompiles)
+INCLUDE (TestBigEndian)
+
+
+### System checks -- mandatory support
+
+# 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)
+
+# getifaddrs ?
+CHECK_FUNCTION_EXISTS (getifaddrs HAVE_GETIFADDRS)
+IF (NOT HAVE_GETIFADDRS)
+ MESSAGE(SEND_ERROR "The getifaddrs function is currently required by freeDiameter.")
+ENDIF (NOT HAVE_GETIFADDRS)
+
+
+### System checks -- for freeDiameter-host.h
+
+# Check byte ordering
+TEST_BIG_ENDIAN(HOST_BIG_ENDIAN)
+
+# Check if ntohll is provided on the system
+CHECK_SYMBOL_EXISTS(ntohll netinet/in.h HAVE_NTOHLL)
+
+# malloc.h ?
+CHECK_INCLUDE_FILES (malloc.h HAVE_MALLOC_H)
+
+# strndup ? Missing on OS X
+CHECK_FUNCTION_EXISTS (strndup HAVE_STRNDUP)
+
+
+### System checks -- for includes / link
+
+# pthreads
+INCLUDE(FindThreads)
+SET(CMAKE_THREAD_LIBS_INIT ${CMAKE_THREAD_LIBS_INIT} PARENT_SCOPE)
+
+# clock_gettime
+SET(HAVE_CLOCK_GETTIME "")
+CHECK_FUNCTION_EXISTS (clock_gettime HAVE_NATIVE_CLOCK_GETTIME)
+IF (HAVE_NATIVE_CLOCK_GETTIME)
+ SET(CLOCK_GETTIME_LIBS "")
+ SET(HAVE_CLOCK_GETTIME 1)
+ELSE (HAVE_NATIVE_CLOCK_GETTIME)
+ CHECK_LIBRARY_EXISTS (rt clock_gettime "" HAVE_LIBRT)
+ IF (HAVE_LIBRT)
+ SET(CLOCK_GETTIME_LIBS "-lrt")
+ SET(HAVE_CLOCK_GETTIME 1)
+ ELSE (HAVE_LIBRT)
+ CHECK_LIBRARY_EXISTS (posix4 clock_gettime "" HAVE_LIBPOSIX4)
+ IF (HAVE_LIBPOSIX4)
+ SET(CLOCK_GETTIME_LIBS "-lposix4")
+ SET(HAVE_CLOCK_GETTIME 1)
+ ENDIF (HAVE_LIBPOSIX4)
+ ENDIF (HAVE_LIBRT)
+ENDIF (HAVE_NATIVE_CLOCK_GETTIME)
+SET(CLOCK_GETTIME_LIBS ${CLOCK_GETTIME_LIBS} PARENT_SCOPE)
+
+# dlopen and dlclose: CMAKE_DL_LIBS
+
+# We need the sctp_connectx function among others
+# 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_connectx HAVE_NATIVE_SCTP)
+ IF(NOT HAVE_NATIVE_SCTP)
+ FIND_PACKAGE(SCTP REQUIRED)
+ ENDIF(NOT HAVE_NATIVE_SCTP)
+ # Now check the number of args of this function, since it changed between Ubuntu 9.04 and 9.10
+ SET(CHECK_SCTP_CONNECTX_4_ARGS_SOURCE_CODE "
+ #include <unistd.h>
+ #include <netinet/sctp.h>
+ int main() {
+ return sctp_connectx(0, NULL, 0, NULL);
+ }
+ ")
+ SET(CMAKE_REQUIRED_INCLUDES ${SCTP_INCLUDE_DIR})
+ SET(CMAKE_REQUIRED_LIBRARIES ${SCTP_LIBRARIES})
+ CHECK_C_SOURCE_COMPILES("${CHECK_SCTP_CONNECTX_4_ARGS_SOURCE_CODE}" SCTP_CONNECTX_4_ARGS)
+ELSE (NOT DISABLE_SCTP)
+ MESSAGE(STATUS "Disabled SCTP support.")
+ENDIF(NOT DISABLE_SCTP)
+SET(SCTP_INCLUDE_DIR ${SCTP_INCLUDE_DIR} PARENT_SCOPE)
+SET(SCTP_LIBRARIES ${SCTP_LIBRARIES} PARENT_SCOPE)
+
+# IDNA process: we use libidn from GNU (unless the function & header files are included in libc)
+IF(NOT DIAMID_IDNA_IGNORE AND NOT DIAMID_IDNA_REJECT)
+ FIND_PACKAGE(IDNA)
+ SET(CHECK_IDNA_SOURCE_CODE "
+ #include <idna.h>
+ int main() {
+ return idna_to_ascii_8z(NULL, NULL, 0);
+ }
+ ")
+ SET(CMAKE_REQUIRED_INCLUDES ${IDNA_INCLUDE_DIR})
+ SET(CMAKE_REQUIRED_LIBRARIES ${IDNA_LIBRARIES})
+ CHECK_C_SOURCE_COMPILES("${CHECK_IDNA_SOURCE_CODE}" HAS_IDNA_SUPPORT)
+ IF(NOT HAS_IDNA_SUPPORT)
+ MESSAGE(SEND_ERROR "Unable to find idna.h header or idna_to_ascii_8z function, please install libidn-dev or equivalent, or set DIAMID_IDNA_IGNORE or DIAMID_IDNA_REJECT")
+ ENDIF(NOT HAS_IDNA_SUPPORT)
+ELSE (NOT DIAMID_IDNA_IGNORE AND NOT DIAMID_IDNA_REJECT)
+ MESSAGE(STATUS "Non-default Internationalized Domain Names (IDN) behavior selected (no stringprep).")
+ENDIF(NOT DIAMID_IDNA_IGNORE AND NOT DIAMID_IDNA_REJECT)
+SET(IDNA_INCLUDE_DIR ${IDNA_INCLUDE_DIR} PARENT_SCOPE)
+SET(IDNA_LIBRARIES ${IDNA_LIBRARIES} PARENT_SCOPE)
+
+
+# Require GNU TLS for building the library
+FIND_PACKAGE(GnuTLS REQUIRED)
+SET(GNUTLS_INCLUDE_DIR ${GNUTLS_INCLUDE_DIR} PARENT_SCOPE)
+SET(GNUTLS_LIBRARIES ${GNUTLS_LIBRARIES} PARENT_SCOPE)
+
+find_path(GCRYPT_INCLUDE_DIR NAMES gcrypt.h)
+If ( NOT GCRYPT_INCLUDE_DIR )
+ MESSAGE(SEND_ERROR "Unable to find gcrypt.h, please install libgcrypt-dev or equivalent")
+Endif ( NOT GCRYPT_INCLUDE_DIR )
+MARK_AS_ADVANCED(GCRYPT_INCLUDE_DIR)
+SET(GCRYPT_INCLUDE_DIR ${GCRYPT_INCLUDE_DIR} PARENT_SCOPE)
+
+# Also we need libgcrypt to... display its version :(
+find_library(GCRYPT_LIBRARY
+ NAMES gcrypt
+)
+If ( NOT GCRYPT_LIBRARY )
+ MESSAGE(SEND_ERROR "Unable to find libgcrypt, please install libgcrypt or equivalent")
+Endif ( NOT GCRYPT_LIBRARY )
+SET(GCRYPT_LIBRARY ${GCRYPT_LIBRARY} PARENT_SCOPE)
+
+
+# Check if AI_ADDRCONFIG is available on the system
+CHECK_SYMBOL_EXISTS(AI_ADDRCONFIG "netdb.h" HAVE_AI_ADDRCONFIG)
+
+
+# Check if barriers are available (for test_fifo)
+SET(CMAKE_REQUIRED_INCLUDES "pthread.h")
+SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+CHECK_FUNCTION_EXISTS (pthread_barrier_wait HAVE_PTHREAD_BAR)
+SET(HAVE_PTHREAD_BAR ${HAVE_PTHREAD_BAR} PARENT_SCOPE)
+
+
+##########################
+
+# Additional hg version when relevant, stored in version.h
+if (EXISTS "${CMAKE_SOURCE_DIR}/.hg")
+ # Search for hg binary to use
+ FIND_PROGRAM(HGCOMMAND hg)
+ if (HGCOMMAND)
+ # Ok, add the custom target so that hg is executed at every build
+ ADD_CUSTOM_TARGET(version_information
+ COMMAND ${CMAKE_COMMAND} -D HGCOMMAND="${HGCOMMAND}" -D SRC="${CMAKE_CURRENT_SOURCE_DIR}/version.h.in" -D DST="${CMAKE_CURRENT_BINARY_DIR}/version.h" -P "${CMAKE_SOURCE_DIR}/cmake/Modules/GetVersionWithHg.cmake"
+ DEPENDS "${CMAKE_SOURCE_DIR}/.hg/dirstate"
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ COMMENT "Retrieving version of the hg repository"
+ )
+ else (HGCOMMAND)
+ # Display at least "unknown" rev in this case
+ SET(FD_PROJECT_VERSION_HG "unknown")
+ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
+ ADD_CUSTOM_TARGET(version_information DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/version.h)
+ endif(HGCOMMAND)
+else (EXISTS "${CMAKE_SOURCE_DIR}/.hg")
+ # We use the pure version number without extension
+ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
+ ADD_CUSTOM_TARGET(version_information DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/version.h)
+endif (EXISTS "${CMAKE_SOURCE_DIR}/.hg")
+
+
+##########################
+
+# LFDPROTO_LIBS = libraries required by the libfdproto.
+SET(LFDPROTO_LIBS ${CLOCK_GETTIME_LIBS} ${CMAKE_THREAD_LIBS_INIT} ${IDNA_LIBRARIES} PARENT_SCOPE)
+# And includes paths
+SET(LFDPROTO_INCLUDES ${IDNA_INCLUDE_DIR} PARENT_SCOPE)
+# Dependencies: the libraries required by any code linking to libfdproto.
+SET(LFDPROTO_LINK_INTERFACES ${CMAKE_THREAD_LIBS_INIT} PARENT_SCOPE)
+
+# LFDCORE_LIBS = libraries required by the libfdcore (in addition to libfdproto and its dependencies)
+SET(LFDCORE_LIBS ${CLOCK_GETTIME_LIBS} ${CMAKE_DL_LIBS} ${SCTP_LIBRARIES} ${GCRYPT_LIBRARY} ${GNUTLS_LIBRARIES} PARENT_SCOPE)
+# And includes paths
+SET(LFDCORE_INCLUDES ${SCTP_INCLUDE_DIR} ${GNUTLS_INCLUDE_DIR} ${GCRYPT_INCLUDE_DIR} PARENT_SCOPE)
+# And dependencies
+SET(LFDCORE_LINK_INTERFACES "" PARENT_SCOPE)
+ # We don't force other libraries, the programs will link with what it needs
+ # (such as libgnutls if it uses GNUTLS_DEBUG() macro
+ # or libfdproto if it uses some of its interfaces directly)
+ # See freeDiameterd/CMakeLists.txt for an example.
+
+##########################
+
+# Generate the host.h file
+CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/freeDiameter-host.h.in ${CMAKE_CURRENT_BINARY_DIR}/freeDiameter-host.h)
+
+####
+## INSTALL section ##
+
+# The headers from this directory are required to develop new extensions for freeDiameter.
+INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/freeDiameter-host.h libfdproto.h libfdcore.h extension.h
+ DESTINATION ${INSTALL_HEADERS_SUFFIX}
+ COMPONENT freeDiameter-dev)
+
diff --git a/include/freeDiameter/extension.h b/include/freeDiameter/extension.h
new file mode 100644
index 0000000..1d6ea7f
--- /dev/null
+++ b/include/freeDiameter/extension.h
@@ -0,0 +1,103 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License) *
+* Author: Sebastien Decugis <sdecugis@freediameter.net> *
+* *
+* Copyright (c) 2013, 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 _EXTENSION_H
+#define _EXTENSION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Include definition of freeDiameter API */
+#include <freeDiameter/freeDiameter-host.h>
+#include <freeDiameter/libfdcore.h>
+
+/* Macro that define the entry point of the extension */
+#define EXTENSION_ENTRY(_name, _function, _depends...) \
+const char *fd_ext_depends[] = { _name , ## _depends , NULL }; \
+static int extension_loaded = 0; \
+int fd_ext_init(int major, int minor, char * conffile) { \
+ if ((major != FD_PROJECT_VERSION_MAJOR) \
+ || (minor != FD_PROJECT_VERSION_MINOR)) { \
+ TRACE_ERROR("This extension (" _name ") was compiled for a different version of freeDiameter."); \
+ TRACE_DEBUG(INFO, "daemon %d.%d != ext %d.%d", \
+ major, minor, \
+ FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR); \
+ return EINVAL; \
+ } \
+ if (extension_loaded) { \
+ TRACE_ERROR("Extension (" _name ") cannot be loaded twice!"); \
+ return ENOTSUP; \
+ } \
+ LOG_N("Loading (" _name ") extension."); \
+ return (_function)(conffile); \
+}
+
+#define EXTENSION_ENTRY2(_name, _dictfunc, _rulesfunction, _depends...) \
+EXTENSION_ENTRY(_name, _dictfunc, ## _depends ) \
+int fd_ext_init2(int major, int minor, char * conffile) { \
+ if ((major != FD_PROJECT_VERSION_MAJOR) \
+ || (minor != FD_PROJECT_VERSION_MINOR)) { \
+ TRACE_ERROR("This extension (" _name ") was compiled for a different version of freeDiameter."); \
+ TRACE_DEBUG(INFO, "daemon %d.%d != ext %d.%d", \
+ major, minor, \
+ FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR); \
+ return EINVAL; \
+ } \
+ if (extension_loaded) { \
+ TRACE_ERROR("Extension (" _name ") cannot be loaded twice!"); \
+ return ENOTSUP; \
+ } \
+ extension_loaded++; \
+ return (_rulesfunction)(conffile); \
+} \
+int fd_ext_parselocalrules(char *conffile) { \
+ return (_rulesfunction)(conffile); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EXTENSION_H */
+
+#if 0
+static int dict_entry(char * conffile)
+{
+ int x = (_dictfunc)(conffile); \
+ if (x != 0) return x; \
+ return (_rulesfunction)(conffile); \
+}
+#endif
diff --git a/include/freeDiameter/freeDiameter-host.h.in b/include/freeDiameter/freeDiameter-host.h.in
new file mode 100644
index 0000000..1539b4a
--- /dev/null
+++ b/include/freeDiameter/freeDiameter-host.h.in
@@ -0,0 +1,106 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License) *
+* Author: Sebastien Decugis <sdecugis@freediameter.net> *
+* *
+* Copyright (c) 2015, 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
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#cmakedefine HAVE_NTOHLL
+#cmakedefine HAVE_MALLOC_H
+#cmakedefine HAVE_SIGNALENT_H
+#cmakedefine HAVE_AI_ADDRCONFIG
+#cmakedefine HAVE_CLOCK_GETTIME
+#cmakedefine HAVE_STRNDUP
+#cmakedefine HAVE_PTHREAD_BAR
+
+#cmakedefine HOST_BIG_ENDIAN @HOST_BIG_ENDIAN@
+
+#cmakedefine DISABLE_SCTP
+#cmakedefine DEBUG_SCTP
+#cmakedefine DEBUG_WITH_META
+#cmakedefine SCTP_USE_MAPPED_ADDRESSES
+#cmakedefine SCTP_CONNECTX_4_ARGS
+#cmakedefine SKIP_DLCLOSE
+#cmakedefine DIAMID_IDNA_IGNORE
+#cmakedefine DIAMID_IDNA_REJECT
+#cmakedefine DISABLE_PEER_EXPIRY
+#cmakedefine WORKAROUND_ACCEPT_INVALID_VSAI
+#cmakedefine GNUTLS_VERSION_210
+#cmakedefine GNUTLS_VERSION_212
+#cmakedefine GNUTLS_VERSION_300
+#cmakedefine GNUTLS_VERSION_310
+
+#cmakedefine ERRORS_ON_TODO
+#cmakedefine DEBUG
+
+#cmakedefine FD_PROJECT_BINARY "@FD_PROJECT_BINARY@"
+#cmakedefine FD_PROJECT_NAME "@FD_PROJECT_NAME@"
+#cmakedefine FD_PROJECT_VERSION_MAJOR @FD_PROJECT_VERSION_MAJOR@
+#ifndef FD_PROJECT_VERSION_MAJOR
+# define FD_PROJECT_VERSION_MAJOR 0
+#endif /*FD_PROJECT_VERSION_MAJOR*/
+#cmakedefine FD_PROJECT_VERSION_MINOR @FD_PROJECT_VERSION_MINOR@
+#ifndef FD_PROJECT_VERSION_MINOR
+# define FD_PROJECT_VERSION_MINOR 0
+#endif /*FD_PROJECT_VERSION_MINOR*/
+#cmakedefine FD_PROJECT_VERSION_REV @FD_PROJECT_VERSION_REV@
+#ifndef FD_PROJECT_VERSION_REV
+# define FD_PROJECT_VERSION_REV 0
+#endif /*FD_PROJECT_VERSION_REV*/
+#cmakedefine FD_PROJECT_VERSION_API @FD_PROJECT_VERSION_API@
+#ifndef FD_PROJECT_VERSION_API
+# define FD_PROJECT_VERSION_API 0
+#endif /*FD_PROJECT_VERSION_API*/
+#cmakedefine FD_PROJECT_COPYRIGHT "@FD_PROJECT_COPYRIGHT@"
+
+#cmakedefine DEFAULT_CONF_PATH "@DEFAULT_CONF_PATH@"
+#cmakedefine DEFAULT_EXTENSIONS_PATH "@DEFAULT_EXTENSIONS_PATH@"
+
+#ifndef FD_DEFAULT_CONF_FILENAME
+#define FD_DEFAULT_CONF_FILENAME "freeDiameter.conf"
+#endif /* FD_DEFAULT_CONF_FILENAME */
+
+/* Maximum number of hooks handlers that can be registered. Make this compilation option if needed */
+#define FD_HOOK_HANDLE_LIMIT 5
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FD_IS_CONFIG */
diff --git a/include/freeDiameter/libfdcore.h b/include/freeDiameter/libfdcore.h
new file mode 100644
index 0000000..a28a542
--- /dev/null
+++ b/include/freeDiameter/libfdcore.h
@@ -0,0 +1,1211 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License) *
+* Author: Sebastien Decugis <sdecugis@freediameter.net> *
+* *
+* Copyright (c) 2016, 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 _LIBFDCORE_H
+#define _LIBFDCORE_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <freeDiameter/libfdproto.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+/* GNUTLS version */
+#ifndef GNUTLS_VERSION
+#define GNUTLS_VERSION LIBGNUTLS_VERSION
+#endif /* GNUTLS_VERSION */
+
+/* GNUTLS calls debug level */
+#ifndef GNUTLS_DBG_LEVEL
+#define GNUTLS_DBG_LEVEL ANNOYING
+#endif /* GNUTLS_DBG_LEVEL */
+
+
+/* Check the return value of a GNUTLS function, log and propagate */
+#define CHECK_GNUTLS_GEN( faillevel, __call__, __fallback__ ) { \
+ CHECK_PRELUDE(__call__); \
+ if (__ret__ < 0) { \
+ LOG(faillevel, "TLS ERROR: in '%s' :\t%s", #__call__ , gnutls_strerror(__ret__)); \
+ __fallback__; \
+ } \
+}
+
+/* we use this macro to help debugging gnutls usage issues -- just change the content to display what you need */
+#define GNUTLS_TRACE( __call__) { \
+ TRACE_CALL("Check: %s", #__call__ ); \
+ (__call__); \
+}
+
+
+#ifndef EXCLUDE_DEPRECATED
+/* Macro for transition, replace with CHECK_GNUTLS_GEN */
+#define CHECK_GNUTLS_DO( __call__, __fallback__ ) \
+ CHECK_GNUTLS_GEN( FD_LOG_ERROR, __call__, __fallback__ )
+
+#endif /* EXCLUDE_DEPRECATED */
+
+
+/*============================================================*/
+/* INITIALIZATION */
+/*============================================================*/
+
+
+/* Initialize the libfdcore internals. This also initializes libfdproto */
+int fd_core_initialize(void);
+
+/* A string describing the version of the library */
+extern const char fd_core_version[];
+
+/* Parse the freeDiameter.conf configuration file, load the extensions */
+int fd_core_parseconf(const char * conffile);
+
+/* Start the server & client threads */
+int fd_core_start(void);
+
+/* Block until the framework has completed its initialization -- useful for extensions */
+int fd_core_waitstartcomplete(void);
+
+/* Initialize shutdown of the framework */
+int fd_core_shutdown(void);
+
+/* Wait for the shutdown to be complete -- this should always be called after fd_core_shutdown */
+int fd_core_wait_shutdown_complete(void);
+
+
+/*============================================================*/
+/* CONFIG */
+/*============================================================*/
+
+/* Structure to hold the configuration of the freeDiameter daemon */
+#define EYEC_CONFIG 0xC011F16
+struct fd_config {
+ int cnf_eyec; /* Eye catcher: EYEC_CONFIG */
+
+ const char *cnf_file; /* Configuration file to parse, default is DEFAULT_CONF_FILE */
+
+ DiamId_t cnf_diamid; /* Diameter Identity of the local peer (FQDN -- ASCII) */
+ size_t cnf_diamid_len;/* cached length of the previous string */
+ DiamId_t cnf_diamrlm; /* Diameter realm of the local peer, default to realm part of cnf_diamid */
+ size_t cnf_diamrlm_len;/* length of the previous string */
+
+ unsigned int cnf_timer_tc; /* The value in seconds of the default Tc timer */
+ unsigned int cnf_timer_tw; /* The value in seconds of the default Tw timer */
+
+ uint16_t cnf_port; /* the local port for legacy Diameter (default: 3868) in host byte order */
+ uint16_t cnf_port_tls; /* the local port for Diameter/TLS (default: 5868) in host byte order */
+ uint16_t cnf_port_3436; /* Open an additional server port to listen to old TLS/SCTP clients (RFC3436, freeDiameter versions < 1.2.0) */
+ uint16_t cnf_sctp_str; /* default max number of streams for SCTP associations (def: 30) */
+ struct fd_list cnf_endpoints; /* the local endpoints to bind the server to. list of struct fd_endpoint. default is empty (bind all). After servers are started, this is the actual list of endpoints including port information. */
+ int cnf_thr_srv; /* Number of threads per servers handling the connection state machines */
+ struct fd_list cnf_apps; /* Applications locally supported (except relay, see flags). Use fd_disp_app_support to add one. list of struct fd_app. */
+ uint16_t cnf_dispthr; /* Number of dispatch threads to create */
+ struct {
+ unsigned no_fwd : 1; /* the peer does not relay messages (0xffffff app id) */
+ unsigned no_ip4 : 1; /* disable IP */
+ unsigned no_ip6 : 1; /* disable IPv6 */
+ unsigned no_tcp : 1; /* disable use of TCP */
+ unsigned no_sctp: 1; /* disable the use of SCTP */
+ unsigned pr_tcp : 1; /* prefer TCP over SCTP */
+ unsigned tls_alg: 1; /* TLS algorithm for initiated cnx. 0: separate port. 1: inband-security (old) */
+ } cnf_flags;
+
+ struct {
+ int tls_disabled;
+
+ /* Credentials parameters (backup) */
+ char * cert_file;
+ char * key_file;
+
+ char * ca_file;
+ int ca_file_nr;
+ char * crl_file;
+
+ char * prio_string;
+ unsigned int dh_bits;
+ char * dh_file;
+
+ /* GNUTLS parameters */
+ gnutls_priority_t prio_cache;
+ gnutls_dh_params_t dh_cache;
+
+ /* GNUTLS server credential(s) */
+ gnutls_certificate_credentials_t credentials; /* contains local cert + trust anchors */
+ #ifdef GNUTLS_VERSION_300
+ gnutls_x509_trust_list_t trustlist; /* the logic to check local certificate has changed */
+ #endif /* GNUTLS_VERSION_300 */
+
+ } cnf_sec_data;
+
+ uint32_t cnf_orstateid; /* The value to use in Origin-State-Id, default to random value */
+ struct dictionary *cnf_dict; /* pointer to the global dictionary */
+ struct fifo *cnf_main_ev; /* events for the daemon's main (struct fd_event items) */
+};
+extern struct fd_config *fd_g_config; /* The pointer to access the global configuration, initalized in main */
+
+
+
+/*============================================================*/
+/* PEERS */
+/*============================================================*/
+
+/* States of a peer */
+enum peer_state {
+ /* Stable states */
+ STATE_NEW = 0, /* The peer has been just been created, PSM thread not started yet */
+ STATE_OPEN, /* Connexion established */
+
+ /* Peer state machine */
+ STATE_CLOSED, /* No connection established, will re-attempt after TcTimer. */
+ STATE_CLOSING, /* the connection is being shutdown (DPR/DPA in progress) */
+ STATE_WAITCNXACK, /* Attempting to establish transport-level connection */
+ STATE_WAITCNXACK_ELEC, /* Received a CER from this same peer on an incoming connection (other peer object), while we were waiting for cnx ack */
+ STATE_WAITCEA, /* Connection established, CER sent, waiting for CEA */
+ /* STATE_WAITRETURNS_ELEC, */ /* This state is not stable and therefore deprecated:
+ We have sent a CER on our initiated connection, and received a CER from the remote peer on another connection. Election.
+ If we win the election, we must disconnect the initiated connection and send a CEA on the other => we go to OPEN state.
+ If we lose, we disconnect the other connection (receiver) and fallback to WAITCEA state. */
+ STATE_OPEN_HANDSHAKE, /* TLS Handshake and validation are in progress in open state -- we use it only for debug purpose, it is never displayed */
+
+ /* Failover state machine */
+ STATE_SUSPECT, /* A DWR was sent and not answered within TwTime. Failover in progress. */
+ STATE_REOPEN, /* Connection has been re-established, waiting for 3 DWR/DWA exchanges before putting back to service */
+
+ /* Ordering issues with multistream & state machine. -- see top of p_psm.c for explanation */
+ STATE_OPEN_NEW, /* after CEA is sent, until a new message is received. Force ordering in this state */
+ STATE_CLOSING_GRACE, /* after DPA is sent or received, give a short delay for messages in the pipe to be received. */
+
+ /* Error state */
+ STATE_ZOMBIE /* The PSM thread is not running anymore; it must be re-started or peer should be deleted. */
+#define STATE_MAX STATE_ZOMBIE
+};
+/* The following macro is called in freeDiameter/p_psm.c */
+#define DECLARE_STATE_STR() \
+const char *peer_state_str[] = { \
+ "STATE_NEW" \
+ , "STATE_OPEN" \
+ , "STATE_CLOSED" \
+ , "STATE_CLOSING" \
+ , "STATE_WAITCNXACK" \
+ , "STATE_WAITCNXACK_ELEC" \
+ , "STATE_WAITCEA" \
+ , "STATE_OPEN_HANDSHAKE" \
+ , "STATE_SUSPECT" \
+ , "STATE_REOPEN" \
+ , "STATE_OPEN_NEW" \
+ , "STATE_CLOSING_GRACE" \
+ , "STATE_ZOMBIE" \
+ };
+extern const char *peer_state_str[];
+#define STATE_STR(state) \
+ (((unsigned)(state)) <= STATE_MAX ? peer_state_str[((unsigned)(state)) ] : "<Invalid>")
+
+/* Constants for the peer_info structure below */
+#define PI_P3_DEFAULT 0 /* Use any available protocol */
+#define PI_P3_IP 1 /* Use only IP to connect to this peer */
+#define PI_P3_IPv6 2 /* resp, IPv6 */
+
+#define PI_P4_DEFAULT 0 /* Attempt any available protocol */
+#define PI_P4_TCP 1 /* Only use TCP */
+#define PI_P4_SCTP 2 /* Only use SCTP */
+
+#define PI_ALGPREF_SCTP 0 /* SCTP is attempted first (default) */
+#define PI_ALGPREF_TCP 1 /* TCP is attempted first */
+
+#define PI_SEC_DEFAULT 0 /* New TLS security (handshake after connection, protecting also CER/CEA) */
+#define PI_SEC_NONE 1 /* Transparent security with this peer (IPsec) */
+#define PI_SEC_TLS_OLD 2 /* Old TLS security (use Inband-Security-Id AVP during CER/CEA) */
+ /* Set sec = 3 to authorize use of (Inband-Security-Id == NONE) with this peer, sec = 2 only authorizing TLS */
+
+#define PI_SCTPSEC_DEF 0 /* Use DTLS over SCTP to connect to this peer (default) */
+#define PI_SCTPSEC_3436 1 /* Use TLS over SCTP to connect to this peer (RFC3436) */
+
+#define PI_EXP_NONE 0 /* the peer entry does not expire */
+#define PI_EXP_INACTIVE 1 /* the peer entry expires (i.e. is deleted) after pi_lft seconds without activity */
+
+#define PI_PRST_NONE 0 /* the peer entry is deleted after disconnection / error */
+#define PI_PRST_ALWAYS 1 /* the peer entry is persistant (will be kept as ZOMBIE in case of error) */
+
+/* Information about a remote peer */
+struct peer_info {
+
+ DiamId_t pi_diamid; /* (supposedly) UTF-8, \0 terminated. The Diameter Identity of the remote peer. */
+ size_t pi_diamidlen; /* cached length of pi_diamid */
+
+ struct {
+ struct {
+ unsigned pro3 :2; /* PI_P3_* */
+ unsigned pro4 :2; /* PI_P4_* */
+ unsigned alg :1; /* PI_ALGPREF_* */
+ unsigned sec :2; /* PI_SEC_* */
+ unsigned sctpsec :1; /* PI_SCTPSEC_* */
+ unsigned exp :1; /* PI_EXP_* */
+ unsigned persist :1; /* PI_PRST_* */
+
+ } pic_flags; /* Flags influencing the connection to the remote peer */
+
+ DiamId_t pic_realm; /* If configured, the daemon will check the received realm in CER/CEA matches this. */
+ uint16_t pic_port; /* port to connect to. 0: default. */
+
+ uint32_t pic_lft; /* lifetime of this peer when inactive (see pic_flags.exp definition) */
+ int pic_tctimer; /* use this value for TcTimer instead of global, if != 0 */
+ int pic_twtimer; /* use this value for TwTimer instead of global, if != 0 */
+
+ char * pic_priority; /* Priority string for GnuTLS if we don't use the default */
+
+ } config; /* Configured data (static for this peer entry) */
+
+ struct {
+
+ /* enum peer_state pir_state; */
+ /* Since 1.1.0, read the state with fd_peer_getstate(peer). */
+
+ DiamId_t pir_realm; /* The received realm in CER/CEA. */
+ size_t pir_realmlen; /* length of the realm */
+
+ uint32_t pir_vendorid; /* Content of the Vendor-Id AVP, or 0 by default */
+ uint32_t pir_orstate; /* Origin-State-Id value */
+ os0_t pir_prodname; /* copy of Product-Name AVP (\0 terminated) */
+ uint32_t pir_firmrev; /* Content of the Firmware-Revision AVP */
+ int pir_relay; /* The remote peer advertized the relay application */
+ struct fd_list pir_apps; /* applications advertised by the remote peer, except relay (pi_flags.relay) */
+ int pir_isi; /* Inband-Security-Id advertised (PI_SEC_* bits) */
+
+ uint32_t pir_lastDC; /* The last Disconnect-Cause value received */
+
+ int pir_proto; /* The L4 protocol currently used with the peer (IPPROTO_TCP or IPPROTO_SCTP) */
+ const gnutls_datum_t *pir_cert_list; /* The (valid) credentials that the peer has presented, or NULL if TLS is not used */
+ /* This is inspired from http://www.gnu.org/software/gnutls/manual/gnutls.html#ex_003ax509_002dinfo
+ see there for example of using this data */
+ unsigned int pir_cert_list_size; /* Number of certificates in the list */
+
+ } runtime; /* Data populated after connection, may change between 2 connections -- not used by fd_peer_add */
+
+ struct fd_list pi_endpoints; /* Endpoint(s) of the remote peer (configured, discovered, or advertized). list of struct fd_endpoint. DNS resolved if empty. */
+};
+
+
+struct peer_hdr {
+ struct fd_list chain; /* Link into the list of all the peers, ordered by their Diameter Id (fd_os_cmp) */
+ struct peer_info info; /* The public data */
+
+ /* This header is followed by more data in the private peer structure definition */
+};
+
+/* the global list of peers.
+ Since we are not expecting so many connections, we don't use a hash, but it might be changed.
+ The list items are peer_hdr structures (actually, fd_peer, but the cast is OK) */
+extern struct fd_list fd_g_peers;
+extern pthread_rwlock_t fd_g_peers_rw; /* protect the list */
+
+/*
+ * FUNCTION: fd_peer_add
+ *
+ * PARAMETERS:
+ * info : Information to create the peer.
+ * orig_dbg : A string indicating the origin of the peer information, for debug (ex: conf, redirect, ...)
+ * cb : optional, a callback to call (once) when the peer connection is established or failed
+ * cb_data : opaque data to pass to the callback.
+ *
+ * DESCRIPTION:
+ * Add a peer to the list of peers to which the daemon must maintain a connexion.
+ *
+ * The content of info parameter is copied, except for the list of endpoints if
+ * not empty, which is simply moved into the created object. It means that the list
+ * items must have been malloc'd, so that they can be freed.
+ *
+ * If cb is not null, the callback is called when the connection is in OPEN state or
+ * when an error has occurred. The callback should use the pi_state information to
+ * determine which one it is. If the first parameter of the called callback is NULL, it
+ * means that the peer is being destroyed before attempt success / failure.
+ * cb is called to allow freeing cb_data in * this case.
+ *
+ * The orig_dbg string is only useful for easing debug, and can be left to NULL.
+ *
+ * RETURN VALUE:
+ * 0 : The peer is added.
+ * EINVAL : A parameter is invalid.
+ * EEXIST : A peer with the same Diameter-Id is already in the list.
+ * (other standard errors may be returned, too, with their standard meaning. Example:
+ * ENOMEM : Memory allocation for the new object element failed.)
+ */
+int fd_peer_add ( struct peer_info * info, const char * orig_dbg, void (*cb)(struct peer_info *, void *), void * cb_data );
+
+/*
+ * FUNCTION: fd_peer_getbyid
+ *
+ * PARAMETERS:
+ * diamid : an UTF8 string describing the diameter Id of the peer to seek
+ * diamidlen : length of the diamid
+ * igncase : perform an almost-case-insensitive search? (slower)
+ * peer : The peer is stored here if it exists.
+ *
+ * DESCRIPTION:
+ * Search a peer by its Diameter-Id.
+ *
+ * RETURN VALUE:
+ * 0 : *peer has been updated (to NULL if the peer is not found).
+ * !0 : An error occurred.
+ */
+int fd_peer_getbyid( DiamId_t diamid, size_t diamidlen, int igncase, struct peer_hdr ** peer );
+
+/*
+ * FUNCTION: fd_peer_get_state
+ *
+ * PARAMETERS:
+ * peer : The peer which state to read
+ *
+ * DESCRIPTION:
+ * Returns the current state of the peer.
+ *
+ * RETURN VALUE:
+ * -1 : peer is invalid
+ * >=0 : the state of the peer at the time of reading.
+ */
+int fd_peer_get_state(struct peer_hdr *peer);
+
+/*
+ * FUNCTION: fd_peer_cnx_proto_info
+ *
+ * PARAMETERS:
+ * peer : The peer which information to be read
+ * buf : Where to store the protocol information
+ * len : available space in bug
+ *
+ * DESCRIPTION:
+ * Creates a string describing the current connection to this peer, e.g.: "TCP,TLS,soc#3".
+ *
+ * RETURN VALUE:
+ * 0 : buffer was written
+ * >=0 : error code.
+ */
+int fd_peer_cnx_proto_info(struct peer_hdr *peer, char * buf, size_t len);
+
+/*
+ * FUNCTION: fd_peer_get_load_pending
+ *
+ * PARAMETERS:
+ * peer : The peer which load to read
+ * to_receive : (out) number of requests sent to this peer without matching answer yet.
+ * to_send : (out) number of requests received from this peer and not yet answered.
+ *
+ * DESCRIPTION:
+ * Returns the current number of requests sent to this peer
+ * that have not been answered yet. This is an empirical indication
+ * of the workload of this peer.
+ *
+ * RETURN VALUE:
+ * 0 : The load parameter has been updated. (it should have a positive value always)
+ * !0 : An error occurred
+ */
+int fd_peer_get_load_pending(struct peer_hdr *peer, long * to_receive, long * to_send);
+
+/*
+ * FUNCTION: fd_peer_validate_register
+ *
+ * PARAMETERS:
+ * peer_validate : Callback as defined below.
+ *
+ * DESCRIPTION:
+ * Add a callback to authorize / reject incoming peer connections.
+ * All registered callbacks are called until a callback sets auth = -1 or auth = 1.
+ * If no callback returns a clear decision, the default behavior is applied (reject unknown connections)
+ * The callbacks are called in FILO order of their registration.
+ *
+ * RETURN VALUE:
+ * 0 : The callback is added.
+ * !0 : An error occurred.
+ */
+int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */, int (**cb2)(struct peer_info *)) );
+/*
+ * CALLBACK: peer_validate
+ *
+ * PARAMETERS:
+ * info : Structure containing information about the peer attempting the connection.
+ * auth : Store there the result if the peer is accepted (1), rejected (-1), or unknown (0).
+ * cb2 : If != NULL and in case of PI_SEC_TLS_OLD, another callback to call after handshake (if auth = 1).
+ *
+ * DESCRIPTION:
+ * This callback is called when a new connection is being established from an unknown peer,
+ * after the CER is received. An extension must register such callback with peer_validate_register.
+ *
+ * The callback can learn if the peer has sent Inband-Security-Id AVPs in runtime.pir_isi fields.
+ * It can also learn if a handshake has already been performed in runtime.pir_cert_list field.
+ * The callback must set the value of config.pic_flags.sec appropriately to allow a connection without TLS.
+ *
+ * If the old TLS mechanism is used,
+ * the extension may also need to check the credentials provided during the TLS
+ * exchange (remote certificate). For this purpose, it may set the address of a new callback
+ * to be called once the handshake is completed. This new callback receives the information
+ * structure as parameter (with pir_cert_list set) and returns 0 if the credentials are correct,
+ * or an error code otherwise. If the error code is received, the connection is closed and the
+ * peer is destroyed.
+ * Note that freeDiameter already achieves some usual checks. The callback may be used to enforce
+ * additional restrictions.
+ *
+ * RETURN VALUE:
+ * 0 : The authorization decision has been written in the location pointed by auth.
+ * !0 : An error occurred.
+ */
+
+
+
+/*============================================================*/
+/* MESSAGES */
+/*============================================================*/
+
+/*
+ * FUNCTION: fd_msg_send, fd_msg_send_timeout
+ *
+ * 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 corresponding answer is received, when sending a request (not used with answers)
+ * anscb_data : opaque data to be passed back to the anscb (or expirecb) when it is called.
+ * expirecb : (only for fd_msg_send_timeout) If the request did not get an answer before timeout, this callback is called.
+ * timeout : (only for fd_msg_send_timeout) sets the absolute time until when to wait for an answer. Past this time,
+ * the expirecb is called with the request and the answer will be discarded if received later.
+ *
+ * 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_answer_from_req.
+ *
+ * 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 fd_disp_register)
+ * - or provide a anscb callback here. If such callback is provided, it is called before the dispatch callbacks.
+ * The prototype for this anscb 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 (fd_msg_free).
+ * note2: the opaque data is not freed by the daemon in any case, extensions should ensure clean handling in fd_ext_fini.
+ *
+ * If no callback is registered to handle an answer, the message is discarded and an error is logged.
+ *
+ * fd_msg_send_timeout is similar to fd_msg_send, except that it takes two additional arguments "expirecb" and "timeout".
+ * If the message parameter is an answer, there is no difference with fd_msg_send.
+ * Otherwise, if the corresponding answer (or error) is received before the timeout date elapses, everything occurs as with fd_msg_send.
+ * Otherwise, the request is removed from the queue (meaning the matching answer will be discarded upon reception) and passed to the expirecb
+ * function. Upon return, if the *msg parameter is not NULL, it is freed (not passed to other callbacks).
+ * expirecb is called in a dedicated thread.
+ *
+ * The prototype for the expirecb callback function is:
+ * void expirecb(void * data, struct peer_hdr * sentto, struct msg ** request)
+ * where:
+ * data : opaque data that was registered along with the callback.
+ * sentto : pointer to the peer to which the message was sent and no answer received within timeout.
+ * request: location of the pointer to the request that was not answered.
+ *
+ * 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 );
+int fd_msg_send_timeout ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout );
+
+/*
+ * FUNCTION: fd_msg_rescode_set
+ *
+ * PARAMETERS:
+ * msg : A msg object -- it must be an answer.
+ * 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, char * rescode, char * errormsg, struct avp * optavp, int type_id );
+
+/* Add Origin-Host, Origin-Realm, (if osi) Origin-State-Id AVPS at the end of the message */
+int fd_msg_add_origin ( struct msg * msg, int osi );
+
+/* Generate a new Session-Id and add it at the beginning of the message (opt is added at the end of the sid if provided) */
+int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen );
+
+
+/* Parse a message against our dictionary,
+ return 0 in case of success.
+ log parsing error & return error code in case of failure in parsing.
+ In addition, if the error code is EBADMSG (the message does not follow our dictionary)
+ if *msg was a request, *msg is NULL and *error contains the error message ready to send back on return
+ if *msg was an answer, *msg is untouched and *error==*msg if *msg was an error message, *error is null otherwise */
+int fd_msg_parse_or_error( struct msg ** msg, struct msg **error );
+
+
+
+
+/*============================================================*/
+/* DISPATCH */
+/*============================================================*/
+
+/*
+ * FUNCTION: fd_disp_app_support
+ *
+ * PARAMETERS:
+ * app : The dictionary object corresponding to the Application.
+ * vendor : (Optional) the dictionary object of a Vendor to claim support in Vendor-Specific-Application-Id
+ * auth : Support auth app part.
+ * acct : Support acct app part.
+ *
+ * DESCRIPTION:
+ * Registers an application to be advertized in CER/CEA exchanges.
+ * Messages with an application-id matching a registered value are passed to the dispatch module,
+ * while other messages are simply relayed or an error is returned (if local node does not relay)
+ *
+ * RETURN VALUE:
+ * 0 : The application support is registered.
+ * EINVAL : A parameter is invalid.
+ */
+int fd_disp_app_support ( struct dict_object * app, struct dict_object * vendor, int auth, int acct );
+
+/* Note: if we want to support capabilities updates, we'll have to add possibility to remove an app as well... */
+
+
+/*============================================================*/
+/* ROUTING */
+/*============================================================*/
+
+/* This file contains the definitions of types and functions involved in the routing decisions in freeDiameter,
+ * and that can be called by extensions.
+ *
+ * Three different type of messages must be distinguished:
+ * - Messages received, and the peer is final recipient (IN messages)
+ * - Messages received, and the peer is not final recipient (FWD messages)
+ * - Message is locally generated (OUT messages)
+ *
+ * There are three global message queues (in queues.c) and also peers-specific queues (in struct fd_peer).
+ *
+ * (*) IN messages processing details:
+ * - the message is received from the remote peer, a FDEVP_CNX_MSG_RECV event is generated for the peer.
+ * - the PSM thread parses the buffer, does some verifications, handles non routable messages (fd_msg_is_routable)
+ * - routable messages are queued in the fd_g_incoming global queue.
+ * - a thread (routing-in) picks the message and takes the decision if it is handled locally or forwarded,
+ * based on local capabilities (registered by extensions with fd_disp_app_support).
+ * - If the message is handled locally, it is queued in fd_g_local.
+ * - Another thread (dispatch.c) will handle this message and pass it to registered callbacks (see fd_disp_register in libfreeDiameter.h).
+ *
+ * (*) FWD messages details:
+ * - The process is the same as for IN messages, until the routing-in threads makes its decision that the message is not handled locally.
+ * - If the local peer does not relay message, an error DIAMETER_APPLICATION_UNSUPPORTED is returned.
+ * - All callbacks registered with fd_rt_fwd_register are called for the message (see below).
+ * - these callbacks will typically do proxying work. Note that adding the route-record is handled by the daemon.
+ * - Once all callbacks have been called, the message is queued in the global fd_g_outgoing queue.
+ * - The remaining processing is the same as for OUT messages, as described below.
+ *
+ * (*) OUT messages details:
+ * - The message are picked from fd_g_outgoing (they are queued there as result of forwarding process or call to fd_msg_send.)
+ * - The (routing-out) thread builds a list of possible destinations for the message, as follow:
+ * - create a list of all known peers in the "OPEN" state.
+ * - remove from that list all peers that are in a Route-Record AVP of the message, to avoid routing loops.
+ * - remove also all peers that have previously replied an error message for this message.
+ * - If the list is empty, create an error UNABLE_TO_DELIVER (note: should we trig dynamic discovery here???) and reply.
+ * - Otherwise, call all callbacks registered by function fd_rt_out_register, with the list of peers and the message.
+ * - Order the resulting list of peers by score (see below), and sent the message to the peer with highest (positive) score.
+ * - in case the peer is no longer in the "OPEN" state, send the message to the second peer in the list.
+ * - if no peer is in OPEN state anymore, restart the process of creating the list.
+ * - Once a peer has been selected, the message is queued into that peer's outgoing queue.
+ *
+ * The following functions allow an extension to register or remove a callback as described above.
+ */
+
+/********** Forwarding callbacks: for Proxy operations ***********/
+
+/* Handle to registered callback */
+struct fd_rt_fwd_hdl;
+
+/* Message direction for the callback */
+enum fd_rt_fwd_dir {
+ RT_FWD_REQ = 1, /* The callback will be called on forwarded requests only */
+ RT_FWD_ALL = 2, /* The callback will be called on all forwarded messages (requests and answers )*/
+ RT_FWD_ANS = 3 /* The callback will be called on answers and errors only */
+};
+
+/*
+ * FUNCTION: fd_rt_fwd_register
+ *
+ * PARAMETERS:
+ * rt_fwd_cb : The callback function to register (see prototype below).
+ * cbdata : Pointer to pass to the callback when it is called. The data is opaque to the daemon.
+ * dir : One of the RT_FWD_* directions defined above.
+ * handler : On success, a handler to the registered callback is stored here.
+ * This handler will be used to unregister the cb.
+ *
+ * DESCRIPTION:
+ * Register a new callback for forwarded messages. See explanations above.
+ * Note that there is no guaranteed order for the callbacks calls.
+ *
+ * RETURN VALUE:
+ * 0 : The callback is registered.
+ * EINVAL : A parameter is invalid.
+ * ENOMEM : Not enough memory to complete the operation
+ */
+int fd_rt_fwd_register ( int (*rt_fwd_cb)(void * cbdata, struct msg ** msg), void * cbdata, enum fd_rt_fwd_dir dir, struct fd_rt_fwd_hdl ** handler );
+/*
+ * CALLBACK: rt_fwd_cb
+ *
+ * PARAMETERS:
+ * data : pointer to some data that was passed when the callback was registered (optional).
+ * msg : The message that is being forwarded.
+ *
+ * DESCRIPTION:
+ * This callback is called when a message is forwarded to another peer. It may for example add a Proxy-Info AVP.
+ * The callback may also choose to handle the message in a more complex form. In that case, it must set *msg = NULL
+ * and handle it differently. In such case, the forwarding thread will stop processing this message.
+ *
+ * RETURN VALUE:
+ * 0 : Operation complete.
+ * !0 : An error occurred -- will result in daemon's termination.
+ */
+
+/*
+ * FUNCTION: fd_rt_fwd_unregister
+ *
+ * PARAMETERS:
+ * handler : The handler of the callback that must be unregistered.
+ * cbdata : Will receive the data registered with the callback, that can be freed if needed.
+ *
+ * DESCRIPTION:
+ * Removes a callback from the list of registered callbacks.
+ *
+ * RETURN VALUE:
+ * 0 : The callback is unregistered.
+ * EINVAL : A parameter is invalid.
+ */
+int fd_rt_fwd_unregister ( struct fd_rt_fwd_hdl * handler, void ** cbdata );
+
+
+/********** Out callbacks: for next hop routing decision operations ***********/
+
+/* Handle to registered callback */
+struct fd_rt_out_hdl;
+
+enum fd_rt_out_score {
+ FD_SCORE_NO_DELIVERY = -70, /* We should not send this message to this candidate */
+ FD_SCORE_SENT_REDIRECT = -60, /* If this peer previously sent a Redirect indication that applies to this message */
+ FD_SCORE_INI = -2, /* All candidates are initialized with this value */
+ FD_SCORE_LOAD_BALANCE = 1, /* Use this to differentiate between several peers with the same score */
+ FD_SCORE_DEFAULT = 5, /* The peer is a default route for all messages */
+ FD_SCORE_DEFAULT_REALM = 10, /* The peer is a default route for this realm */
+ FD_SCORE_REALM = 15, /* The peer belongs to Destination-Realm of the message */
+ FD_SCORE_REDIR_HOST = 25, /* If there is a redirect rule with ALL_HOST for these message and peer */
+ FD_SCORE_REDIR_APP = 30, /* If there is a redirect rule with ALL_APPLICATION for these message and peer */
+ FD_SCORE_REDIR_REALM = 35, /* If there is a redirect rule with ALL_REALM for these message and peer */
+ FD_SCORE_REDIR_REALM_APP = 40, /* If there is a redirect rule with REALM_AND_APPLICATION for these message and peer */
+ FD_SCORE_REDIR_USER = 45, /* If there is a redirect rule with ALL_USER for these message and peer */
+ FD_SCORE_REDIR_SESSION = 50, /* If there is a redirect rule with ALL_SESSION for these message and peer */
+ FD_SCORE_REDIR_ONCE = 55, /* If there is a redirect rule with DONT_CACHE for these message and peer */
+ FD_SCORE_FINALDEST = 100 /* If the peer is the final recipient of the message (i.e. matching Destination-Host), it receives a big score. */
+};
+
+/*
+ * FUNCTION: fd_rt_out_register
+ *
+ * PARAMETERS:
+ * rt_out_cb : The callback function to register (see prototype below).
+ * cbdata : Pointer to pass to the callback when it is called. The data is opaque to the daemon.
+ * priority : Order for calling this callback. The callbacks are called in reverse priority order (higher priority = called sooner).
+ * handler : On success, a handler to the registered callback is stored here.
+ * This handler will be used to unregister the cb.
+ *
+ * DESCRIPTION:
+ * Register a new callback to handle OUT routing decisions. See explanations above.
+ *
+ * RETURN VALUE:
+ * 0 : The callback is registered.
+ * EINVAL : A parameter is invalid.
+ * ENOMEM : Not enough memory to complete the operation
+ */
+int fd_rt_out_register ( int (*rt_out_cb)(void * cbdata, struct msg ** pmsg, struct fd_list * candidates), void * cbdata, int priority, struct fd_rt_out_hdl ** handler );
+/*
+ * CALLBACK: rt_out_cb
+ *
+ * PARAMETERS:
+ * cbdata : pointer to some data that was registered with the callback.
+ * pmsg : pointer to the message that must be sent. upon return if *msg is NULL, the processing stops and the message is not sent.
+ * list : The list of peers to which the message may be sent to, as returned by fd_rtd_candidate_extract
+ *
+ * DESCRIPTION:
+ * This callback must attribute a score (preferably from FD_SCORE_*) to each candidate peer in the list.
+ * Once all registered callbacks have been called, the message is sent to the candidate with the highest score.
+ * Note that each callback must *add* its locally-attributed score to the candidate current "score" parameter, not replace it!
+ * Note also that this callback must be re-entrant since it may be called by several threads at the same time
+ * (for different messages)
+ *
+ * RETURN VALUE:
+ * 0 : Operation complete.
+ * !0 : An error occurred.
+ */
+
+/*
+ * FUNCTION: fd_rt_out_unregister
+ *
+ * PARAMETERS:
+ * handler : The handler of the callback that must be unregistered.
+ * cbdata : Will receive the data registered with the callback, that can be freed if needed.
+ *
+ * DESCRIPTION:
+ * Removes a callback from the list of registered callbacks.
+ *
+ * RETURN VALUE:
+ * 0 : The callback is unregistered.
+ * EINVAL : A parameter is invalid.
+ */
+int fd_rt_out_unregister ( struct fd_rt_out_hdl * handler, void ** cbdata );
+
+
+/*============================================================*/
+/* EVENTS */
+/*============================================================*/
+
+struct fd_event {
+ int code; /* codespace depends on the queue */
+ size_t size;
+ void *data;
+};
+
+/* Daemon's codespace: 1000->1999 (1500->1999 defined in fdcore-internal.h) */
+enum {
+ FDEV_TERMINATE_INT= 1000 /* request to terminate. DO NOT USE. Use fd_core_shutdown() instead. */
+ ,FDEV_TRIGGER /* Trigger available for extensions. size is sizeof(int), data is int * */
+};
+
+int fd_event_send(struct fifo *queue, int code, size_t datasz, void * data);
+int fd_event_get(struct fifo *queue, int * code, size_t * datasz, void ** data);
+int fd_event_timedget(struct fifo *queue, struct timespec * timeout, int timeoutcode, int * code, size_t * datasz, void ** data);
+void fd_event_destroy(struct fifo **queue, void (*free_cb)(void * data));
+const char * fd_ev_str(int event);
+
+/* for extensions */
+int fd_event_trig_regcb(int trigger_val, const char * module, void (*cb)(void));
+
+#ifndef SWIG
+DECLARE_FD_DUMP_PROTOTYPE(fd_event_trig_dump);
+
+/* The "old" FD_EV_DUMP_* events are replaced with direct calls to the following dump functions */
+DECLARE_FD_DUMP_PROTOTYPE(fd_conf_dump);
+
+DECLARE_FD_DUMP_PROTOTYPE(fd_ext_dump);
+#else /* SWIG */
+DECLARE_FD_DUMP_PROTOTYPE_simple(fd_event_trig_dump);
+DECLARE_FD_DUMP_PROTOTYPE_simple(fd_conf_dump);
+DECLARE_FD_DUMP_PROTOTYPE_simple(fd_ext_dump);
+#endif /* SWIG */
+DECLARE_FD_DUMP_PROTOTYPE(fd_servers_dump, int details);
+DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump_list, int details);
+DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump, struct peer_hdr * p, int details);
+
+/*============================================================*/
+/* ENDPOINTS */
+/*============================================================*/
+
+struct fd_endpoint {
+ struct fd_list chain; /* link in cnf_endpoints list */
+
+ union {
+ sSS ss; /* the socket information. List is always ordered by ss value (memcmp) -- see fd_ep_add_merge */
+ sSA4 sin;
+ sSA6 sin6;
+ sSA sa;
+ }
+#ifdef SWIG /* nested anonymous unions are not supported yet */
+ s
+#endif /* SWIG */
+ ;
+
+#define EP_FL_CONF (1 << 0) /* This endpoint is statically configured in a configuration file */
+#define EP_FL_DISC (1 << 1) /* This endpoint was resolved from the Diameter Identity or other DNS query */
+#define EP_FL_ADV (1 << 2) /* This endpoint was advertized in Diameter CER/CEA exchange */
+#define EP_FL_LL (1 << 3) /* Lower layer mechanism provided this endpoint */
+#define EP_FL_PRIMARY (1 << 4) /* This endpoint is primary in a multihomed SCTP association */
+#define EP_ACCEPTALL (1 << 15) /* This flag allows bypassing the address filter in fd_ep_add_merge. */
+ uint32_t flags; /* Additional information about the endpoint */
+
+ /* To add: a validity timestamp for DNS records ? How do we retrieve this lifetime from DNS ? */
+};
+
+int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, uint32_t flags );
+int fd_ep_filter( struct fd_list * list, uint32_t flags );
+int fd_ep_filter_family( struct fd_list * list, int af );
+int fd_ep_clearflags( struct fd_list * list, uint32_t flags );
+DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump_one, int preamble, struct fd_endpoint * ep );
+DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump, int preamble, int indent, struct fd_list * eps );
+
+
+/*============================================================*/
+/* APPLICATIONS IDs */
+/*============================================================*/
+
+struct fd_app {
+ struct fd_list chain; /* link in cnf_apps list. List ordered by appid. */
+ struct {
+ unsigned auth : 1;
+ unsigned acct : 1;
+ } flags;
+ vendor_id_t vndid; /* if not 0, Vendor-Specific-App-Id AVP will be used */
+ application_id_t appid; /* The identifier of the application */
+};
+
+int fd_app_merge(struct fd_list * list, application_id_t aid, vendor_id_t vid, int auth, int acct);
+int fd_app_check(struct fd_list * list, application_id_t aid, struct fd_app **detail);
+int fd_app_check_common(struct fd_list * list1, struct fd_list * list2, int * common_found);
+int fd_app_empty(struct fd_list * list);
+
+
+
+/*============================================================*/
+/* MONITORING */
+/*============================================================*/
+
+/* These functions allow an extension to collect state information about the
+ * framework, as well as being hooked at some key checkpoints in the processing
+ * for logging or statistics purpose.
+ */
+
+
+/* CALLBACK: fd_hook_cb
+ *
+ * PARAMETERS:
+ * type : The type of hook that triggered this call, in case same cb is registered for several hooks.
+ * msg : If relevant, the pointer to the message triggering the call. NULL otherwise.
+ * peer : If relevant, the pointer to the peer associated with the call. NULL otherwise.
+ * other : For some callbacks, the remaining information is passed in this parameter. See each hook detail.
+ * permsgdata : Structure associated with a given message, across several hooks.
+ * A different structure is associated with requests and corresponding answers.
+ * See fd_hook_data_hdl below for details.
+ * If no fd_hook_data_hdl is registered with this callback, this parameter is always NULL
+ * regdata : Data pointer stored at registration, opaque for the framework.
+ *
+ * DESCRIPTION:
+ * When such callback is registered with fd_hook_register function, it will be called on matching events with
+ * the parameters as described in the list of fd_hook_type below. One can use this mechanism for e.g.:
+ * - log completely the messages for safety / backup
+ * - create statistics information on the throughput
+ * - ...
+ *
+ * IMPORTANT: the callback MUST NOT change the memory pointed by the different parameters (peer, message, ...)
+ *
+ * RETURN VALUE:
+ * none.
+ */
+
+/* The available hooks in the framework */
+enum fd_hook_type {
+
+ HOOK_DATA_RECEIVED = 0,
+ /* Hook called as soon as a message has been received from the network, after TLS & boundary processing.
+ - {msg} is NULL.
+ - {peer} is NULL.
+ - {other} is a pointer to a struct fd_cnx_rcvdata containing the received buffer.
+ - {permsgdata} points to either a new empty structure allocated for this message (cf. fd_hook_data_hdl), or NULL if no hdl is registered.
+ */
+
+ HOOK_MESSAGE_RECEIVED,
+ /* Hook called when a message has been received and the structure has been parsed successfully (list of AVPs).
+ - {msg} points to the parsed message. At this time, the objects have not been dictionary resolved. If you
+ try to call fd_msg_parse_dict, it will slow down the operation of a relay agent.
+ - {peer} is set if the message is received from a peer's connection, and NULL if the message is from a new client
+ connected and not yet identified
+ - {other} is NULL, or a char * identifying the connection when {peer} is null.
+ - {permsgdata} points to either a new empty structure allocated for this message or the one passed to HOOK_DATA_RECEIVED if used.
+ */
+
+ HOOK_MESSAGE_LOCAL,
+ /* Hook called when a request message has been created locally by an extension and is being sent.
+ - {msg} points to the message.
+ - {peer} is NULL
+ - {other} is NULL
+ - {permsgdata} points to a new empty structure allocated for this request (cf. fd_hook_data_hdl)
+ */
+
+ HOOK_MESSAGE_SENDING,
+ /* Hook called when a message is about to be sent to a peer. The message pointer cannot be modified here, but the content of the message
+ could still be changed (for example add or remove some AVP. This is the last chance.
+ - {msg} points to the message. Some objects may not have been dictionary resolved. If you
+ try to call fd_msg_parse_dict, it will slow down the operation of the instance.
+ - {peer} is the one the message is being sent to.
+ - {other} is NULL.
+ - {permsgdata} points to existing structure if any, or a new structure otherwise.
+ */
+
+ HOOK_MESSAGE_SENT,
+ /* Hook called when a message has been sent to a peer. The message might be freed as soon as the hook function returns,
+ so it is not safe to store the pointer for asynchronous processing.
+ - {msg} points to the sent message. Again, the objects may not have been dictionary resolved. If you
+ try to call fd_msg_parse_dict, it will slow down the operation of a relay agent.
+ - {peer} is set if the message is sent to a peer's connection, and NULL if the message is sent to a new client
+ connected and not yet identified, or being rejected
+ - {other} is NULL.
+ - {permsgdata} points to existing structure if any, or a new structure otherwise.
+ */
+
+ HOOK_MESSAGE_FAILOVER,
+ /* Hook called when a message that was sent to a peer is being requeued, because e.g. the connection was torn down.
+ In that case the message will go again through the routing process.
+ - {msg} points to the corresponding request message (the answer is discarded). Again, the objects may not have been dictionary resolved. If you
+ try to call fd_msg_parse_dict, it might slow down the operation of a relay agent, although this hook is not on the normal execution path.
+ - {peer} is the peer this message was previously sent to.
+ - {other} is NULL.
+ - {permsgdata} points to existing structure if any, or a new structure otherwise.
+ */
+
+ HOOK_MESSAGE_PARSING_ERROR,
+ /* Hook called when a message being processed cannot be parsed successfully.
+ - {msg} points to the message if buffer was parsed successfully, or NULL otherwise. You should not call fd_msg_parse_dict on this in any case.
+ - {peer} is NULL or the peer that received the message. If NULL and the message is not NULL, you can still retrieve the source from the message itself.
+ - {other} is a char * pointer to the error message (human-readable) if {msg} is not NULL, a pointer to struct fd_cnx_rcvdata containing the received buffer otherwise.
+ - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered).
+ */
+
+ HOOK_MESSAGE_ROUTING_ERROR,
+ /* Hook called when a message being processed by the routing thread meets an error such as no remaining available peer for sending, based on routing callbacks decisions (maybe after retries).
+ - {msg} points to the message. Again, the objects may not have been dictionary resolved. If you
+ try to call fd_msg_parse_dict, it might slow down the operation of a relay agent, although this hook is not on the normal execution path.
+ - {peer} is NULL.
+ - {other} is a char * pointer to the error message (human-readable).
+ - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered).
+ */
+
+ HOOK_MESSAGE_ROUTING_FORWARD,
+ /* Hook called when a received message is deemed to be not handled locally by the routing_dispatch process.
+ The decision of knowing which peer it will be sent to is not made yet (or if an error will be returned).
+ The hook is trigged before the callbacks registered with fd_rt_fwd_register are called.
+ - {msg} points to the message. Again, the objects may not have been dictionary resolved.
+ If you try to call fd_msg_parse_dict, it will slow down the operation of a relay agent.
+ - {peer} is NULL.
+ - {other} is NULL.
+ - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered).
+ */
+
+ HOOK_MESSAGE_ROUTING_LOCAL,
+ /* Hook called when a received message is handled locally by the routing_dispatch process (i.e., not forwarded).
+ The hook is trigged before the callbacks registered with fd_disp_register are called.
+ - {msg} points to the message. Here, the message has been already parsed completely & successfully.
+ - {peer} is NULL.
+ - {other} is NULL.
+ - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered).
+ */
+
+ HOOK_MESSAGE_DROPPED,
+ /* Hook called when a message is being discarded by the framework because of some error condition (normal or abnormal).
+ It is probably a good idea to log this for analysis / backup.
+ - {msg} points to the message, which will be freed as soon as the hook returns.
+ - {peer} may be NULL or a peer related to the event.
+ - {other} is a char * pointer to the error message (human-readable).
+ - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered).
+ */
+
+ HOOK_PEER_CONNECT_FAILED,
+ /* Hook called when a connection attempt to/from a remote peer has failed. This hook is also called when the peer was in OPEN state and the connection is broken.
+ - {msg} may be NULL (lower layer error, e.g. connection timeout) or points to a message showing the error (either invalid incoming message, or the CEA message sent or received with an error code).
+ - {peer} may be NULL for incoming requests from unknown peers being rejected, otherwise it points to the peer structure associated with the attempt.
+ - {other} is a char * pointer to the error message (human-readable).
+ - {permsgdata} is always NULL for this hook.
+ */
+
+ HOOK_PEER_CONNECT_SUCCESS,
+ /* Hook called when a connection attempt to/from a remote peer has succeeded (the peer moves to OPEN_HANDSHAKE or OPEN state).
+ In case of deprecated TLS handshake after the CER/CEA exchange, this hook can still be followed by HOOK_PEER_CONNECT_FAILED if TLS handshake fails.
+ - {msg} points to the CEA message sent or received (with a success code) -- in case it is sent, you can always get access to the matching CER.
+ - {peer} points to the peer structure.
+ - {other} is NULL.
+ - {permsgdata} is always NULL for this hook.
+ */
+
+ HOOK_MESSAGE_PARSING_ERROR2,
+ /* Hook called after an error message has been generated due to a dictionary parsing error.
+ - {msg} points to the error message that has been generated.
+ - {peer} is NULL. You can still retrieve the source from the message itself.
+ - {other} is NULL
+ - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered).
+ Use this hook if you need to populate more data in the error being returned, from the error message.
+ (e.g. some AVP need to be added to replies even if error case.
+ */
+#define HOOK_LAST HOOK_MESSAGE_PARSING_ERROR2
+};
+
+
+/* Type of the {permsgdata} pointer. It is up to each extension to define its own structure. This is opaque for the framework. */
+struct fd_hook_permsgdata;
+
+/* A handle that will be associated with the extension, and with the permsgdata structures. */
+struct fd_hook_data_hdl;
+
+/* The following structure is what is passed to the HOOK_DATA_RECEIVED hook */
+struct fd_cnx_rcvdata {
+ size_t length;
+ uint8_t * buffer; /* internal note: the buffer is padded with a struct fd_msg_pmdl, not accounted for in length */
+};
+
+/* Function to register a new fd_hook_data_hdl. Should be called by your extension init function.
+ * The arguments are the functions called to initialize a new fd_hook_permsgdata and to free this structure when the corresponding message is being freed.
+ */
+/*
+ * FUNCTION: fd_hook_data_register
+ *
+ * PARAMETERS:
+ * permsgdata_size : the size of the fd_hook_permsgdata structure.
+ * permsgdata_init_cb : function called to initialize a new fd_hook_permsgdata structure, when a hook will be called for a message that does not have such structure yet.
+ * The memory is already allocated and blanked, so you can pass NULL if no further handling is required.
+ * permsgdata_fini_cb : function called when a message is being disposed. It should free the resources associated with the fd_hook_permsgdata.
+ * You can pass NULL if no special handling is required. The memory of the permsgdata structure itself will be freed by the framework.
+ * new_handle : On success, a handler to the registered callback is stored here.
+ * This handler will be used to unregister the cb.
+ *
+ * DESCRIPTION:
+ * Register a new fd_hook_data_hdl. This handle is used during hooks registration (see below) in order to associate data with the messages, to allow keeping tracking of the message easily.
+ * Note that these handlers are statically allocated and cannot be unregistered. FD_HOOK_HANDLE_LIMIT handlers can be registered at maximum (recompile libfdproto if you change this value)
+ *
+ * RETURN VALUE:
+ * 0 : The callback is registered.
+ * EINVAL : A parameter is invalid.
+ * ENOSPC : Too many handles already registered. You may need to increase the limit in the code.
+ */
+int fd_hook_data_register(
+ size_t permsgdata_size,
+ void (*permsgdata_init_cb) (struct fd_hook_permsgdata *),
+ void (*permsgdata_fini_cb) (struct fd_hook_permsgdata *),
+ struct fd_hook_data_hdl **new_handle
+);
+
+/* A handler associated with a registered hook callback (for cleanup) */
+struct fd_hook_hdl;
+
+/* Helper for building a mask of hooks for registration */
+#define HOOK_MASK(hooklist...) fd_hook_mask_helper(0, ## hooklist, -1)
+
+/*
+ * FUNCTION: fd_hook_register
+ *
+ * PARAMETERS:
+ * type_mask : A bitmask of fd_hook_type bits for which this cb is registered, e.g. HOOK_MASK( HOOK_MESSAGE_RECEIVED, HOOK_MESSAGE_SENT )
+ * fd_hook_cb : The callback function to register (see prototype above).
+ * regdata : Pointer to pass to the callback when it is called. The data is opaque to the daemon.
+ * data_hdl : If permsgdata is requested for the hooks, a handler registered with fd_hook_data_register. NULL otherwise.
+ * handler : On success, a handler to the registered callback is stored here.
+ * This handler can be used to unregister the cb.
+ *
+ * DESCRIPTION:
+ * Register a new hook in the framework. See explanations above.
+ *
+ * RETURN VALUE:
+ * 0 : The callback is registered.
+ * EEXIST : Another callback is already registered for this type of hook (HOOK_DATA_RECEIVED).
+ * EINVAL : A parameter is invalid.
+ * ENOMEM : Not enough memory to complete the operation
+ */
+int fd_hook_register ( uint32_t type_mask,
+ void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata),
+ void *regdata,
+ struct fd_hook_data_hdl *data_hdl,
+ struct fd_hook_hdl ** handler );
+
+/* Remove a hook registration */
+int fd_hook_unregister( struct fd_hook_hdl * handler );
+
+
+/* Use the following function to retrieve any pmd structure associated with a request matching the current answer. Returns NULL in case of error / no such structure */
+struct fd_hook_permsgdata * fd_hook_get_request_pmd(struct fd_hook_data_hdl *data_hdl, struct msg * answer);
+
+/* The following is used by HOOK_MASK macro */
+uint32_t fd_hook_mask_helper(int dummy, ...);
+
+/*============================================================*/
+
+/*
+ * The following allows an extension to retrieve stat information on the different fifo queues involved in the freeDiameter framework.
+ * There are three global queues, plus per-peer queues.
+ * This information can be used to build SNMP-like data for example, or quickly get a status of the framework to find the loaded path of execution / bottlenecks.
+ */
+enum fd_stat_type {
+ /* For the following, no peer is associated with the stat */
+ STAT_G_LOCAL= 1, /* Get statistics for the global queue of messages processed by local extensions */
+ STAT_G_INCOMING, /* Get statistics for the global queue of received messages to be processed by routing_in thread */
+ STAT_G_OUTGOING, /* Get statistics for the global queue of messages to be processed by routing_out thread */
+
+ /* For the following, the peer must be provided */
+ STAT_P_PSM, /* Peer state machine queue (events to be processed for this peer, including received messages) */
+ STAT_P_TOSEND, /* Queue of messages for sending to this peer */
+};
+
+/*
+ * FUNCTION: fd_stat_getstats
+ *
+ * PARAMETERS:
+ * stat : Which queue is being queried
+ * peer : (depending on the stat parameter) which peer is being queried
+ * current_count : (out) The number of items in the queue currently
+ * limit_count : (out) The max number of items the queue accepts before becoming blocking -- 0 means no max.
+ * highest_count : (out) The highest count the queue has reached since startup
+ * total_count : (out) Total number of items that this queue has processed (always growing, use deltas for monitoring)
+ * total : (out) Cumulated time all items spent in this queue, including blocking time (always growing, use deltas for monitoring)
+ * blocking : (out) Cumulated time threads trying to post new items were blocked (queue full).
+ * last : (out) For the last element retrieved from the queue, how long it took between posting (including blocking) and poping
+ *
+ * DESCRIPTION:
+ * Get statistics information about a given queue.
+ * Any of the (out) parameters can be NULL if not requested.
+ *
+ * RETURN VALUE:
+ * 0 : The callback is registered.
+ * EINVAL : A parameter is invalid.
+ */
+int fd_stat_getstats(enum fd_stat_type stat, struct peer_hdr * peer,
+ int * current_count, int * limit_count, int * highest_count, long long * total_count,
+ struct timespec * total, struct timespec * blocking, struct timespec * last);
+
+/*============================================================*/
+/* EOF */
+/*============================================================*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBFDCORE_H */
diff --git a/include/freeDiameter/libfdproto.h b/include/freeDiameter/libfdproto.h
new file mode 100644
index 0000000..e0d0744
--- /dev/null
+++ b/include/freeDiameter/libfdproto.h
@@ -0,0 +1,3254 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License) *
+* Author: Sebastien Decugis <sdecugis@freediameter.net> *
+* *
+* Copyright (c) 2015, 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 S_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>
+ *
+ * If any change is made to this file, you must increment the FD_PROJECT_VERSION_API version.
+ *
+ * The file contains the following parts:
+ * DEBUG
+ * MACROS
+ * OCTET STRINGS
+ * THREADS
+ * LISTS
+ * DICTIONARY
+ * SESSIONS
+ * MESSAGES
+ * DISPATCH
+ * QUEUES
+ */
+
+#ifndef _LIBFDPROTO_H
+#define _LIBFDPROTO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef FD_IS_CONFIG
+#error "You must include 'freeDiameter-host.h' before this file."
+#endif /* FD_IS_CONFIG */
+
+#include <pthread.h>
+#include <sched.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include <libgen.h> /* for basename */
+
+#ifdef SWIG
+#define _ATTRIBUTE_PRINTFLIKE_(_f,_v)
+#else
+#define _ATTRIBUTE_PRINTFLIKE_(_f,_v) __attribute__ ((format (printf, _f, _v)))
+#endif /* SWIG */
+
+/* Remove some deprecated warnings from some gnutls versions, when possible */
+#if defined(__GNUC__)
+# define GCC_DIAG_DO_PRAGMA(x) _Pragma (#x)
+# define GCC_DIAG_PRAGMA(x) GCC_DIAG_DO_PRAGMA(GCC diagnostic x)
+# if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406 /* 4.6.x */
+# define GCC_DIAG_OFF(x) GCC_DIAG_PRAGMA(push) \
+ GCC_DIAG_PRAGMA(ignored x)
+# define GCC_DIAG_ON(x) GCC_DIAG_PRAGMA(pop)
+# else /* older */
+# define GCC_DIAG_OFF(x) GCC_DIAG_PRAGMA(ignored x)
+# define GCC_DIAG_ON(x) GCC_DIAG_PRAGMA(warning x)
+# endif
+#else
+# define GCC_DIAG_OFF(x)
+# define GCC_DIAG_ON(x)
+#endif
+
+/*============================================================*/
+/* CONSTANTS */
+/*============================================================*/
+
+#define DIAMETER_PORT 3868
+#define DIAMETER_SECURE_PORT 5868
+
+
+/*============================================================*/
+/* INIT */
+/*============================================================*/
+
+/* This function must be called first, before any call to another library function */
+int fd_libproto_init(void); /* note if you are using libfdcore, it handles this already */
+
+/* Call this one when the application terminates, to destroy internal threads */
+void fd_libproto_fini(void);
+
+/* Retrieve the version of the binary */
+extern const char fd_libproto_version[];
+
+/*============================================================*/
+/* DEBUG */
+/*============================================================*/
+
+
+/*
+ * FUNCTION: fd_log
+ *
+ * PARAMETERS:
+ * loglevel : Integer, how important the message is. Valid values are macros FD_LOG_*
+ * format : Same format string as in the printf function
+ * ... : Same list as printf
+ *
+ * DESCRIPTION:
+ * Write information to log.
+ * The format and arguments may contain UTF-8 encoded data. The
+ * output medium is expected to support this encoding.
+ *
+ * RETURN VALUE:
+ * None.
+ */
+void fd_log ( int, const char *, ... ) _ATTRIBUTE_PRINTFLIKE_(2,3);
+#ifndef SWIG
+void fd_log_va( int, const char *, va_list);
+#endif /* SWIG */
+
+/* these are internal objects of the debug facility,
+might be useful to control the behavior from outside */
+extern pthread_mutex_t fd_log_lock;
+extern char * fd_debug_one_function;
+extern char * fd_debug_one_file;
+
+/*
+ * 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 ( const char * name );
+extern pthread_key_t fd_log_thname;
+
+/*
+ * FUNCTION: fd_log_time
+ *
+ * PARAMETERS:
+ * ts : The timestamp to log, or NULL for "now"
+ * buf : An array where the time must be stored
+ * len : size of the buffer
+ * incl_date : The day of year is included in the output
+ * incl_ms : millisecond value is included in the output
+ *
+ * DESCRIPTION:
+ * Writes the timestamp (in human readable format) in a buffer.
+ *
+ * RETURN VALUE:
+ * pointer to buf.
+ */
+char * fd_log_time ( struct timespec * ts, char * buf, size_t len, int incl_date, int incl_ms );
+
+/*
+ * FUNCTION: fd_log_handler_register
+ * MACRO:
+ *
+ * PARAMETERS:
+ * loglevel : priority of the message
+ * format : Same format string as in the printf function
+ * va_list : Argument list
+ *
+ * DESCRIPTION:
+ * Register an external method for logging purposes.
+ *
+ * RETURN VALUE:
+ * int : Success or failure
+ */
+int fd_log_handler_register ( void (*logger)(int loglevel, const char * format, va_list args) );
+
+/*
+ * FUNCTION: fd_log_handler_unregister
+ * MACRO:
+ *
+ * PARAMETERS:
+ *
+ * DESCRIPTION:
+ * Unregister the external logging function.
+ *
+ * RETURN VALUE:
+ * int : Success or failure
+ */
+int fd_log_handler_unregister ( void );
+
+
+/* All dump functions follow this same prototype:
+ * PARAMETERS:
+ * buf : *buf can be NULL on entry, it will be malloc'd. Otherwise it is realloc'd if needed.
+ * len : the current size of the buffer (in/out)
+ * offset: (optional) if provided, starts writing dump at offset in the buffer, and updated upon exit. if NULL, starts at offset O.
+ *
+ * RETURN VALUE:
+ * *buf upon success, NULL upon failure.
+ *
+ * REMARKS:
+ * - After the buffer has been used, it should be freed.
+ * - Depending on the function, the created string may be multi-line. However, it should never be terminated with a '\n'.
+ */
+#define DECLARE_FD_DUMP_PROTOTYPE( function_name, args... ) \
+ char * function_name(char ** buf, size_t *len, size_t *offset, ##args)
+
+#ifdef SWIG
+#define DECLARE_FD_DUMP_PROTOTYPE_simple( function_name ) \
+ char * function_name(char ** buf, size_t *len, size_t *offset)
+#endif /* SWIG */
+
+
+/* Helper functions for the *dump functions that add into a buffer */
+DECLARE_FD_DUMP_PROTOTYPE( fd_dump_extend, const char * format, ... ) _ATTRIBUTE_PRINTFLIKE_(4,5);
+DECLARE_FD_DUMP_PROTOTYPE( fd_dump_extend_hexdump, uint8_t *data, size_t datalen, size_t trunc, size_t wrap );
+
+
+/* Some helpers macro for writing such *_dump routine */
+#define FD_DUMP_STD_PARAMS buf, len, offset
+#define FD_DUMP_HANDLE_OFFSET() size_t o = 0; if (!offset) offset = &o; if (buf && (*buf) && !(*offset)) **buf='\0'
+#define FD_DUMP_HANDLE_TRAIL() while ((*buf) && (*offset > 0) && ((*buf)[*offset - 1] == '\n')) { *offset -= 1; (*buf)[*offset] = '\0'; }
+
+
+
+/*============================================================*/
+/* DEBUG MACROS */
+/*============================================================*/
+
+#ifndef ASSERT
+#define ASSERT(x) assert(x)
+#endif /* ASSERT */
+
+/* log levels definitions, that are passed to the logger */
+#define FD_LOG_ANNOYING 0 /* very verbose loops and such "overkill" traces. Only active when the framework is compiled in DEBUG mode. */
+#define FD_LOG_DEBUG 1 /* Get a detailed sense of what is going on in the framework. Use this level for normal debug */
+#define FD_LOG_NOTICE 3 /* Normal execution states worth noting */
+#define FD_LOG_ERROR 5 /* Recoverable or expected error conditions */
+#define FD_LOG_FATAL 6 /* Unrecoverable error, e.g. malloc fail, etc. that requires the framework to shutdown */
+
+/* The level used by the default logger, can be changed by command-line arguments. Ignored for other loggers. */
+extern int fd_g_debug_lvl;
+
+/* Some portability code to get nice function name in __PRETTY_FUNCTION__ */
+#if (!defined( __func__)) && (__STDC_VERSION__ < 199901L)
+# if __GNUC__ >= 2
+# define __func__ __FUNCTION__
+# else /* __GNUC__ >= 2 */
+# define __func__ "<unknown>"
+# endif /* __GNUC__ >= 2 */
+#endif /*(!defined( __func__)) && (__STDC_VERSION__ < 199901L) */
+#ifndef __PRETTY_FUNCTION__
+#define __PRETTY_FUNCTION__ __func__
+#endif /* __PRETTY_FUNCTION__ */
+
+/* A version of __FILE__ without the full path. This is specific to each C file being compiled */
+static char * file_bname = NULL;
+static char * file_bname_init(char * full) { file_bname = basename(full); return file_bname; }
+#define __STRIPPED_FILE__ (file_bname ?: file_bname_init((char *)__FILE__))
+
+
+
+/* In DEBUG mode, we add meta-information along each trace. This makes multi-threading problems easier to debug. */
+#if (defined(DEBUG) && defined(DEBUG_WITH_META))
+# define STD_TRACE_FMT_STRING "pid:%s in %s@%s:%d: "
+# define STD_TRACE_FMT_ARGS , ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed"), __PRETTY_FUNCTION__, __STRIPPED_FILE__, __LINE__
+#else /* DEBUG && DEBUG_WITH_META */
+# define STD_TRACE_FMT_STRING ""
+# define STD_TRACE_FMT_ARGS
+#endif /* DEBUG && DEBUG_WITH_META */
+
+/*************************
+ The general debug macro
+ *************************/
+#define LOG(printlevel,format,args... ) \
+ fd_log((printlevel), STD_TRACE_FMT_STRING format STD_TRACE_FMT_ARGS, ## args)
+
+/*
+ * Use the following macros in the code to get traces with location & pid in debug mode:
+ */
+#ifdef DEBUG
+# define LOG_A(format,args... ) \
+ do { if ((fd_debug_one_function && !strcmp(fd_debug_one_function, __PRETTY_FUNCTION__)) \
+ || (fd_debug_one_file && !strcmp(fd_debug_one_file, __STRIPPED_FILE__) ) ) { \
+ LOG(FD_LOG_DEBUG,"[DBG_MATCH] " format,##args); \
+ } else { \
+ LOG(FD_LOG_ANNOYING,format,##args); \
+ } } while (0)
+#else /* DEBUG */
+# define LOG_A(format,args... ) /* not defined in release */
+#endif /* DEBUG */
+
+/* Debug information useful to follow in detail what is going on */
+#define LOG_D(format,args... ) \
+ LOG(FD_LOG_DEBUG, format, ##args)
+
+/* Report a normal message that is useful for normal admin monitoring */
+#define LOG_N(format,args... ) \
+ LOG(FD_LOG_NOTICE, format,##args)
+
+/* Report an error */
+#define LOG_E(format,args... ) \
+ LOG(FD_LOG_ERROR, format, ##args)
+
+/* Report a fatal error */
+#define LOG_F(format,args... ) \
+ LOG(FD_LOG_FATAL, format, ##args)
+
+
+/*************
+ Derivatives
+ ************/
+/* Trace a binary buffer content */
+#define LOG_BUFFER(printlevel, prefix, buf, bufsz, suffix ) { \
+ int __i; \
+ size_t __sz = (size_t)(bufsz); \
+ uint8_t * __buf = (uint8_t *)(buf); \
+ char __strbuf[1024+1]; \
+ for (__i = 0; (__i < __sz) && (__i<(sizeof(__strbuf)/2)); __i++) { \
+ sprintf(__strbuf + (2 * __i), "%02hhx", __buf[__i]); \
+ } \
+ fd_log(printlevel, STD_TRACE_FMT_STRING "%s%s%s" STD_TRACE_FMT_ARGS, \
+ (prefix), __strbuf, (suffix)); \
+}
+
+/* Split a multi-line buffer into separate calls to the LOG function. */
+#define LOG_SPLIT(printlevel, per_line_prefix, mlbuf, per_line_suffix ) { \
+ char * __line = (mlbuf), *__next; \
+ char * __p = (per_line_prefix), *__s = (per_line_suffix); \
+ while ((__next = strchr(__line, '\n')) != NULL) { \
+ LOG(printlevel, "%s%.*s%s", __p ?:"", (int)(__next - __line), __line, __s ?:""); \
+ __line = __next + 1; \
+ } \
+ LOG(printlevel, "%s%s%s", __p ?:"", __line, __s ?:""); \
+}
+
+/* Helper for function entry -- for very detailed trace of the execution */
+#define TRACE_ENTRY(_format,_args... ) \
+ LOG_A("[enter] %s(" _format ") {" #_args "}", __PRETTY_FUNCTION__, ##_args );
+
+/* Helper for debugging by adding traces -- for debuging a specific location of the code */
+#define TRACE_HERE() \
+ LOG_F(" -- debug checkpoint %d -- ", fd_breakhere());
+int fd_breakhere(void);
+
+/* Helper for tracing the CHECK_* macros below -- very very verbose code execution! */
+#define TRACE_CALL( str... ) \
+ LOG_A( str )
+
+/* For development only, to keep track of TODO locations in the code */
+#ifndef ERRORS_ON_TODO
+# define TODO( _msg, _args... ) \
+ LOG_F( "TODO: " _msg , ##_args);
+#else /* ERRORS_ON_TODO */
+# define TODO( _msg, _args... ) \
+ "TODO" = _msg ## _args; /* just a stupid compilation error to spot the todo */
+#endif /* ERRORS_ON_TODO */
+
+
+/*============================================================*/
+/* ERROR CHECKING MACRO */
+/*============================================================*/
+
+/* Macros to check a return value and branch out in case of error.
+ * These macro additionally provide the logging information.
+ *
+ * The name "__ret__" is always available in the __fallback__ parameter and contains the error code.
+ */
+
+#define CHECK_PRELUDE(__call__) \
+ int __ret__; \
+ TRACE_CALL("Check: %s", #__call__ ); \
+ __ret__ = (__call__)
+
+#define DEFAULT_FB return __ret__;
+
+/* System check: error case if < 0, error value in errno */
+#define CHECK_SYS_GEN( faillevel, __call__, __fallback__ ) { \
+ CHECK_PRELUDE(__call__); \
+ if (__ret__ < 0) { \
+ __ret__ = errno; \
+ LOG(faillevel, "ERROR: in '%s' :\t%s", #__call__ , strerror(__ret__)); \
+ __fallback__; \
+ } \
+}
+
+
+/* Check the return value of a function and execute fallback in case of error or special value */
+#define CHECK_FCT_GEN2( faillevel, __call__, __speval__, __fallback1__, __fallback2__ ) { \
+ CHECK_PRELUDE(__call__); \
+ if (__ret__ != 0) { \
+ if (__ret__ == (__speval__)) { \
+ __fallback1__; \
+ } else { \
+ LOG(faillevel, "ERROR: in '%s' :\t%s", #__call__ , strerror(__ret__)); \
+ __fallback2__; \
+ } \
+ } \
+}
+
+/* Check the return value of a function and execute fallback in case of error (return value different from 0) */
+#define CHECK_FCT_GEN( faillevel, __call__, __fallback__) \
+ CHECK_FCT_GEN2( faillevel, (__call__), 0, , (__fallback__) )
+
+/* Check that a memory allocator did not return NULL, otherwise log an error and execute fallback */
+#define CHECK_MALLOC_GEN( faillevel, __call__, __fallback__ ) { \
+ void * __ptr__; \
+ TRACE_CALL("Check: %s", #__call__ ); \
+ __ptr__ = (void *)(__call__); \
+ if (__ptr__ == NULL) { \
+ int __ret__ = errno; \
+ LOG(faillevel, "ERROR: in '%s' :\t%s", #__call__ , strerror(__ret__)); \
+ __fallback__; \
+ } \
+}
+
+/* Check parameters at function entry, execute fallback on error */
+#define CHECK_PARAMS_GEN( faillevel, __bool__, __fallback__ ) { \
+ TRACE_CALL("Check: %s", #__bool__ ); \
+ if ( ! (__bool__) ) { \
+ int __ret__ = EINVAL; \
+ LOG(faillevel, "ERROR: invalid parameter '%s'", #__bool__ ); \
+ __fallback__; \
+ } \
+}
+
+
+/*============================================================*/
+/* COMPATIBILITY MACROS, TO BE REMOVED */
+/*============================================================*/
+/* Redefine the old macros for transition of the code */
+#ifndef EXCLUDE_DEPRECATED
+
+#define MARK_DEPRECATED /* __attribute__ ((deprecated)) */
+
+enum old_levels {
+ NONE = 0,
+ INFO = 1,
+ FULL = 2,
+ ANNOYING = 4,
+ FCTS = 6,
+ CALL = 9
+} MARK_DEPRECATED;
+
+static __inline__ int old_TRACE_BOOL( enum old_levels level, const char * file, const char * func ) MARK_DEPRECATED
+{
+ if ((fd_debug_one_function && !strcmp(fd_debug_one_function, func))
+ || (fd_debug_one_file && !strcmp(fd_debug_one_file, file) ))
+ return 2; /* Level override */
+ if ((int)level <= fd_g_debug_lvl)
+ return 1; /* Normal level */
+ return 0; /* No trace */
+}
+#define TRACE_BOOL(level) old_TRACE_BOOL((level), __STRIPPED_FILE__, __PRETTY_FUNCTION__)
+
+#ifndef SWIG
+static __inline__ void fd_log_deprecated( int level, const char *format, ... ) MARK_DEPRECATED
+{
+ va_list ap;
+ va_start(ap, format);
+ fd_log_va(level, format, ap);
+ va_end(ap);
+}
+#else /* SWIG */
+void fd_log_deprecated( int level, const char *format, ... );
+#endif /* SWIG */
+static __inline__ void replace_me() MARK_DEPRECATED { }
+
+#define TRACE_BUFFER(...) replace_me();
+#define TRACE_NOTICE(...) replace_me();
+
+
+/* Use the LOG_* instead, or use the new *_dump functions when dumping an object */
+#define fd_log_debug(format,args...) fd_log_deprecated(FD_LOG_DEBUG, format, ## args)
+#define fd_log_notice(format,args...) fd_log_deprecated(FD_LOG_NOTICE, format, ## args)
+#define fd_log_error(format,args...) fd_log_deprecated(FD_LOG_ERROR, format, ## args)
+
+/* old macro for traces. To be replaced by appropriate LOG_* macros. */
+# define TRACE_DEBUG(oldlevel, format,args... ) { \
+ int __l__; \
+ if ((__l__ = TRACE_BOOL(oldlevel))) { \
+ if (oldlevel <= NONE) { LOG_E(format,##args); } \
+ else if (oldlevel <= INFO) { LOG_N(format,##args); } \
+ else if (__l__ == 2) { LOG_N(format,##args); } \
+ else if (oldlevel <= FULL) { LOG_D(format,##args); } \
+ else { LOG_A(format,##args); } \
+} }
+
+/* the following macro must be replaced with LOG_E or LOG_F */
+# define TRACE_ERROR LOG_E
+
+
+/* The following macros are missing the faillevel information, which indicates at what log level the error case should be displayed. */
+# define CHECK_SYS_DO( __call__, __fallback__ ) { \
+ CHECK_PRELUDE(__call__); \
+ if (__ret__ < 0) { \
+ __ret__ = errno; \
+ TRACE_ERROR("ERROR: in '%s' :\t%s", #__call__ , strerror(__ret__)); \
+ __fallback__; \
+ } \
+}
+
+# define CHECK_SYS( __call__ ) \
+ CHECK_SYS_DO( (__call__), return __ret__ )
+
+
+# define CHECK_POSIX_DO2( __call__, __speval__, __fallback1__, __fallback2__ ) { \
+ CHECK_PRELUDE(__call__); \
+ if (__ret__ != 0) { \
+ if (__ret__ == (__speval__)) { \
+ __fallback1__; \
+ } else { \
+ TRACE_ERROR("ERROR: in '%s' :\t%s", #__call__ , strerror(__ret__)); \
+ __fallback2__; \
+ } \
+ } \
+}
+
+# define CHECK_POSIX_DO( __call__, __fallback__ ) \
+ CHECK_POSIX_DO2( (__call__), 0, , __fallback__ )
+
+# define CHECK_POSIX( __call__ ) \
+ CHECK_POSIX_DO( (__call__), return __ret__ )
+
+# define CHECK_MALLOC_DO( __call__, __fallback__ ) { \
+ void * __ptr__; \
+ TRACE_CALL("Check: %s", #__call__ ); \
+ __ptr__ = (void *)(__call__); \
+ if (__ptr__ == NULL) { \
+ int __ret__ = errno; \
+ TRACE_ERROR("ERROR: in '%s' :\t%s", #__call__ , strerror(__ret__)); \
+ __fallback__; \
+ } \
+}
+
+# define CHECK_MALLOC( __call__ ) \
+ CHECK_MALLOC_DO( (__call__), return __ret__ )
+
+# define CHECK_PARAMS_DO( __bool__, __fallback__ ) { \
+ TRACE_CALL("Check: %s", #__bool__ ); \
+ if ( ! (__bool__) ) { \
+ int __ret__ = EINVAL; \
+ TRACE_ERROR("ERROR: Invalid parameter '%s', %d", #__bool__, __ret__ ); \
+ __fallback__; \
+ } \
+}
+
+# define CHECK_PARAMS( __bool__ ) \
+ CHECK_PARAMS_DO( (__bool__), return __ret__ )
+
+# define CHECK_FCT_DO CHECK_POSIX_DO
+# define CHECK_FCT CHECK_POSIX
+
+#endif /* EXCLUDE_DEPRECATED */
+
+
+/*============================================================*/
+/* Optimized code: remove all debugging code */
+/*============================================================*/
+#ifdef STRIP_DEBUG_CODE
+#undef LOG_D
+#undef LOG_N
+#undef LOG_E
+#undef LOG_F
+#undef LOG_BUFFER
+
+#define LOG_D(format,args... ) /* noop */
+#define LOG_N(format,args...) fd_log(FD_LOG_NOTICE, format, ## args)
+#define LOG_E(format,args...) fd_log(FD_LOG_ERROR, format, ## args)
+#define LOG_F(format,args...) fd_log(FD_LOG_FATAL, format, ## args)
+#define LOG_BUFFER(printlevel, level, prefix, buf, bufsz, suffix ) { \
+ if (printlevel > FD_LOG_DEBUG) { \
+ int __i; \
+ size_t __sz = (size_t)(bufsz); \
+ uint8_t * __buf = (uint8_t *)(buf); \
+ char * __strbuf[1024+1]; \
+ for (__i = 0; (__i < __sz) && (__i<(sizeof(__strbuf)/2); __i++) { \
+ sprintf(__strbuf + (2 * __i), "%02.2hhx", __buf[__i]); \
+ } \
+ fd_log(printlevel, prefix"%s"suffix, __strbuf); \
+ }
+#endif /* STRIP_DEBUG_CODE */
+
+/*============================================================*/
+/* OTHER MACROS */
+/*============================================================*/
+/* helper macros (pre-processor hacks to allow macro arguments) */
+#define __tostr( arg ) #arg
+#define _stringize( arg ) __tostr( arg )
+#define __agr( arg1, arg2 ) arg1 ## arg2
+#define _aggregate( arg1, arg2 ) __agr( arg1, arg2 )
+
+/* 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
+
+/* The sockaddr length of a sSS structure */
+#define sSAlen( _sa_ ) \
+ ( (socklen_t) ( (((sSA *)_sa_)->sa_family == AF_INET) ? (sizeof(sSA4)) : \
+ ((((sSA *)_sa_)->sa_family == AF_INET6) ? (sizeof(sSA6)) : \
+ 0 ) ) )
+#define sSAport( _sa_ ) \
+ ( (socklen_t) ( (((sSA *)_sa_)->sa_family == AF_INET) ? (((sSA4 *)(_sa_))->sin_port) : \
+ ((((sSA *)_sa_)->sa_family == AF_INET6) ? (((sSA6 *)(_sa_))->sin6_port) : \
+ 0 ) ) )
+
+DECLARE_FD_DUMP_PROTOTYPE(fd_sa_dump, sSA * sa, int flags);
+#define sSA_DUMP_STRLEN (INET6_ADDRSTRLEN + 1 + 32 + 2)
+void fd_sa_sdump_numeric(char * buf /* must be at least sSA_DUMP_STRLEN */, sSA * sa);
+
+
+/* A l4 protocol name (TCP / SCTP) */
+#ifdef DISABLE_SCTP
+#define IPPROTO_NAME( _proto ) \
+ (((_proto) == IPPROTO_TCP) ? "TCP" : \
+ "Unknown")
+#else /* DISABLE_SCTP */
+#define IPPROTO_NAME( _proto ) \
+ ( ((_proto) == IPPROTO_TCP) ? "TCP" : \
+ (((_proto) == IPPROTO_SCTP) ? "SCTP" : \
+ "Unknown"))
+#endif /* DISABLE_SCTP */
+
+/* Define the value of IP loopback address */
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK inet_addr("127.0.0.1")
+#endif /* INADDR_LOOPBACK */
+
+#ifndef INADDR_BROADCAST
+#define INADDR_BROADCAST ((in_addr_t) 0xffffffff)
+#endif /* INADDR_BROADCAST */
+
+/* An IP equivalent to IN6_IS_ADDR_LOOPBACK */
+#ifndef IN_IS_ADDR_LOOPBACK
+#define IN_IS_ADDR_LOOPBACK(a) \
+ ((((long int) (a)->s_addr) & ntohl(0xff000000)) == ntohl(0x7f000000))
+#endif /* IN_IS_ADDR_LOOPBACK */
+
+/* An IP equivalent to IN6_IS_ADDR_UNSPECIFIED */
+#ifndef IN_IS_ADDR_UNSPECIFIED
+#define IN_IS_ADDR_UNSPECIFIED(a) \
+ (((long int) (a)->s_addr) == 0x00000000)
+#endif /* IN_IS_ADDR_UNSPECIFIED */
+
+/* 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])
+
+
+/* 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 by the cmake step, 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 give the next multiple of 4 for an integer (used for padding sizes of AVP). */
+#define PAD4(_x) ((_x) + ( (4 - (_x)) & 3 ) )
+
+/* Useful to display any value as (safe) ASCII (will garbage UTF-8 output...) */
+#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_sec == (ts2)->tv_sec ) && ((ts1)->tv_nsec < (ts2)->tv_nsec) ))
+
+/* Compute diff between two timespecs (pointers) */
+#define TS_DIFFERENCE( tsdiff, tsstart, tsend ) { \
+ if ((tsend)->tv_nsec < (tsstart)->tv_nsec ) { \
+ (tsdiff)->tv_sec = (tsend)->tv_sec - (tsstart)->tv_sec - 1; \
+ (tsdiff)->tv_nsec = (tsend)->tv_nsec + 1000000000 - (tsstart)->tv_nsec; \
+ } else { \
+ (tsdiff)->tv_sec = (tsend)->tv_sec - (tsstart)->tv_sec; \
+ (tsdiff)->tv_nsec = (tsend)->tv_nsec - (tsstart)->tv_nsec; \
+ }}
+
+
+/* This gives a good size for buffered reads */
+#ifndef BUFSIZ
+#define BUFSIZ 96
+#endif /* BUFSIZ */
+
+/* This gives the length of a const string */
+#define CONSTSTRLEN( str ) (sizeof(str) - 1)
+
+
+/*============================================================*/
+/* PORTABILITY */
+/*============================================================*/
+#ifndef HAVE_CLOCK_GETTIME
+ #define CLOCK_REALTIME 0
+ #include <sys/time.h>
+ int clock_gettime(int clk_id, struct timespec* ts);
+#endif /* HAVE_CLOCK_GETTIME */
+
+#ifndef HAVE_STRNDUP
+char * strndup (char *str, size_t len);
+#endif /* HAVE_STRNDUP */
+
+
+/*============================================================*/
+/* BINARY STRINGS */
+/*============================================================*/
+
+/* Compute a hash value of a binary string.
+The hash must remain local to this machine, there is no guarantee that same input
+will give same output on a different system (endianness) */
+uint32_t fd_os_hash ( uint8_t * string, size_t len );
+
+/* This type used for binary strings that contain no \0 except as their last character.
+It means some string operations can be used on it. */
+typedef uint8_t * os0_t;
+
+/* Same as strdup but for os0_t strings */
+os0_t os0dup_int(os0_t s, size_t l);
+#define os0dup( _s, _l) (void *)os0dup_int((os0_t)(_s), _l)
+
+/* Check that an octet string value can be used as os0_t */
+static __inline__ int fd_os_is_valid_os0(uint8_t * os, size_t oslen) {
+ /* The only situation where it is not valid is when it contains a \0 inside the octet string */
+ return (memchr(os, '\0', oslen) == NULL);
+}
+
+/* The following type denotes a verified DiameterIdentity value (that contains only pure letters, digits, hyphen, dot) */
+typedef char * DiamId_t;
+
+/* Maximum length of a hostname we accept */
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 512
+#endif /* HOST_NAME_MAX */
+
+/* Check if a binary string contains a valid Diameter Identity value.
+ rfc3588 states explicitely that such a Diameter Identity consists only of ASCII characters. */
+int fd_os_is_valid_DiameterIdentity(uint8_t * os, size_t ossz);
+
+/* The following function validates a string as a Diameter Identity or applies the IDNA transformation on it
+ if *inoutsz is != 0 on entry, *id may not be \0-terminated.
+ memory has the following meaning: 0: *id can be realloc'd. 1: *id must be malloc'd on output (was static)
+*/
+int fd_os_validate_DiameterIdentity(char ** id, size_t * inoutsz, int memory);
+
+/* Create an order relationship for binary strings (not needed to be \0 terminated).
+ It does NOT mimic strings relationships so that it is more efficient. It is case sensitive.
+ (the strings are actually first ordered by their lengh, then by their bytes contents)
+ returns: -1 if os1 < os2; +1 if os1 > os2; 0 if they are equal */
+int fd_os_cmp_int(os0_t os1, size_t os1sz, os0_t os2, size_t os2sz);
+#define fd_os_cmp(_o1, _l1, _o2, _l2) fd_os_cmp_int((os0_t)(_o1), _l1, (os0_t)(_o2), _l2)
+
+/* A roughly case-insensitive variant, which actually only compares ASCII chars (0-127) in a case-insentitive maneer
+ -- it does not support locales where a lowercase letter uses more space than upper case, such as ß -> ss
+ It is slower than fd_os_cmp.
+ Note that the result is NOT the same as strcasecmp !!!
+
+ This function gives the same order as fd_os_cmp, except when it finds 2 strings to be equal.
+ However this is not always sufficient:
+ for example fd_os_cmp gives: "Ac" < "aB" < "aa"
+ if you attempt to fd_os_almostcasesrch "Aa" you will actually have to go past "aB" which is > "Aa".
+ Therefore you can use the maybefurther parameter.
+ This parameter is 1 on return if os1 may have been stored further that os2 (assuming os2 values are ordered by fd_os_cmp)
+ and 0 if we are sure that it is not the case.
+ When looping through a list of fd_os_cmp classified values, this parameter must be used to stop looping, in addition to the comp result.
+ */
+int fd_os_almostcasesrch_int(uint8_t * os1, size_t os1sz, uint8_t * os2, size_t os2sz, int * maybefurther);
+#define fd_os_almostcasesrch(_o1, _l1, _o2, _l2, _mb) fd_os_almostcasesrch_int((os0_t)(_o1), _l1, (os0_t)(_o2), _l2, _mb)
+
+/* Analyze a DiameterURI and return its components.
+ Return EINVAL if the URI is not valid.
+ *diamid is malloc'd on function return and must be freed (it is processed by fd_os_validate_DiameterIdentity).
+ *secure is 0 (no security) or 1 (security enabled) on return.
+ *port is 0 (default) or a value in host byte order on return.
+ *transport is 0 (default) or IPPROTO_* on return.
+ *proto is 0 (default) or 'd' (diameter), 'r' (radius), or 't' (tacacs+) on return.
+ */
+int fd_os_parse_DiameterURI(uint8_t * uri, size_t urisz, DiamId_t * diamid, size_t * diamidlen, int * secure, uint16_t * port, int * transport, char *proto);
+
+/*============================================================*/
+/* THREADS */
+/*============================================================*/
+
+/* Terminate a thread */
+static __inline__ int fd_thr_term(pthread_t * th)
+{
+ 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( pthread_join(*th, &th_ret) );
+
+ if (th_ret == PTHREAD_CANCELED) {
+ TRACE_DEBUG(ANNOYING, "The thread %p was canceled", (void *)*th);
+ } else {
+ TRACE_DEBUG(CALL, "The thread %p returned %p", (void *)*th, th_ret);
+ }
+
+ /* Clean the location */
+ *th = (pthread_t)NULL;
+
+ return 0;
+}
+
+
+/*************
+ Cancelation cleanup handlers for common objects
+ *************/
+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);
+}
+static __inline__ void fd_cleanup_socket(void * sockptr)
+{
+ if (sockptr && (*(int *)sockptr > 0)) {
+ CHECK_SYS_DO( close(*(int *)sockptr), /* ignore */ );
+ *(int *)sockptr = -1;
+ }
+}
+
+
+/*============================================================*/
+/* 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 pointer, used for any purpose (ex: start of the parent object) */
+};
+
+/* Initialize a list element */
+#define FD_LIST_INITIALIZER( _list_name ) \
+ { .next = & _list_name, .prev = & _list_name, .head = & _list_name, .o = NULL }
+#define FD_LIST_INITIALIZER_O( _list_name, _obj ) \
+ { .next = & _list_name, .prev = & _list_name, .head = & _list_name, .o = _obj }
+void fd_list_init ( struct fd_list * list, void * obj );
+
+/* Return boolean, true if the list is empty */
+#define FD_IS_LIST_EMPTY( _list ) ((((struct fd_list *)(_list))->head == (_list)) && (((struct 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 );
+
+/* Move all elements from a list at the end of another */
+void fd_list_move_end(struct fd_list * ref, struct fd_list * senti);
+
+/* Insert an item in an ordered list -- ordering function must be 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 );
+
+
+
+
+/*============================================================*/
+/* 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 below 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 below 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 below 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, const 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 */
+DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump_object, struct dict_object * obj);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump, struct dictionary * dict);
+
+/* Function to access full contents of the dictionary, see doc in dictionary.c */
+int fd_dict_getlistof(int criteria, void * parent, struct fd_list ** sentinel);
+
+/* Function to remove an entry from the dictionary.
+ This cannot be used if the object has children (for example a vendor with vendor-specific AVPs).
+ In such case, the children must be removed first. */
+int fd_dict_delete(struct dict_object * obj);
+
+/*
+ ***************************************************************************
+ *
+ * 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 char * */
+ VENDOR_OF_APPLICATION, /* "what" points to a struct dict_object containing an application (see below) */
+ VENDOR_OF_AVP, /* "what" points to a struct dict_object containing an avp (see below) */
+};
+
+/***
+ * 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.
+
+- fd_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 = fd_dict_new ( dict, DICT_VENDOR, &myvendordata, NULL, &myvendor );
+ }
+
+- fd_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 = fd_dict_search ( dict, DICT_VENDOR, VENDOR_BY_ID, &vendorid, &vendor_found, ENOENT);
+ - or -
+ ret = fd_dict_search ( dict, DICT_VENDOR, VENDOR_BY_NAME, "my vendor name", &vendor_found, ENOENT);
+ }
+
+ - fd_dict_getval:
+ Sample code to retrieve the data from a vendor object:
+ {
+ int ret;
+ struct dict_object * myvendor;
+ struct dict_vendor_data myvendordata;
+ ret = fd_dict_search ( dict, DICT_VENDOR, VENDOR_BY_NAME, "my vendor name", &myvendor, ENOENT);
+ ret = fd_dict_getval ( myvendor, &myvendordata );
+ printf("my vendor id: %d\n", myvendordata.vendor_id );
+ }
+
+*/
+
+/* Special function: */
+uint32_t * fd_dict_get_vendorid_list(struct dictionary * dict);
+
+/*
+ ***************************************************************************
+ *
+ * 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 char * */
+ APPLICATION_OF_TYPE, /* "what" points to a struct dict_object containing a type object (see below) */
+ APPLICATION_OF_COMMAND /* "what" points to a struct dict_object containing a command (see below) */
+};
+
+/***
+ * 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.
+
+- fd_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 = fd_dict_new ( dict, DICT_VENDOR, &vendor_data, NULL, &vendor );
+ ret = fd_dict_new ( dict, DICT_APPLICATION, &app_data, vendor, &appl );
+ }
+
+- fd_dict_search:
+ Sample code to retrieve the vendor of an application
+ {
+ int ret;
+ struct dict_object * vendor, * appli;
+
+ ret = fd_dict_search ( dict, DICT_APPLICATION, APPLICATION_BY_NAME, "my vendor's application", &appli, ENOENT);
+ ret = fd_dict_search ( dict, DICT_VENDOR, VENDOR_OF_APPLICATION, appli, &vendor, ENOENT);
+ }
+
+ - fd_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 = fd_dict_search ( dict, DICT_APPLICATION, APPLICATION_BY_NAME, "my vendor's application", &appli, ENOENT);
+ ret = fd_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 */
+ 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);
+
+/*
+ * CALLBACK: dict_avpdata_check
+ *
+ * PARAMETERS:
+ * val : Pointer to the AVP value that was received and needs to be sanity checked.
+ * data : a parameter stored in the type structure (to enable more generic check functions)
+ * error_msg: upon erroneous value, a string describing the error can be returned here (it will be strcpy by caller). This description will be returned in the error message, if any.
+ *
+ * DESCRIPTION:
+ * This callback can be provided with a derived type in order to improve the operation of the
+ * fd_msg_parse_dict function. When this callback is present, the value of the AVP that has
+ * been parsed is passed to this function for finer granularity check. For example for some
+ * speccific AVP, the format of an OCTETSTRING value can be further checked, or the
+ * interger value can be verified.
+ *
+ * RETURN VALUE:
+ * 0 : The value is valid.
+ * !0 : An error occurred, the error code is returned. It is advised to return EINVAL on incorrect val
+ */
+typedef int (*dict_avpdata_check) (void * data, union avp_value * val, char ** error_msg);
+
+
+
+/* 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) */
+ DECLARE_FD_DUMP_PROTOTYPE((*type_dump), union avp_value * val); /* cb called by fd_msg_dump_* for this type of data (if != NULL). Returned string must be freed. */
+ dict_avpdata_check type_check;
+ void * type_check_param;
+};
+
+/* The criteria for searching a type object in the dictionary */
+enum {
+ TYPE_BY_NAME = 30, /* "what" points to a char * */
+ TYPE_OF_ENUMVAL, /* "what" points to a struct dict_object containing an enumerated constant (DICT_ENUMVAL, see below). */
+ TYPE_OF_AVP /* "what" points to a struct dict_object containing an AVP object. */
+};
+
+/****
+ Callbacks defined in libfdproto/dictionary_functions.c file -- see that file for usage.
+ */
+
+/* Convert an Address type AVP into a struct sockaddr_storage */
+int fd_dictfct_Address_encode(void * data, union avp_value * avp_value);
+int fd_dictfct_Address_interpret(union avp_value * avp_value, void * interpreted);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Address_dump, union avp_value * avp_value);
+
+/* Display the content of an AVP of type UTF8String in the log file */
+DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_UTF8String_dump, union avp_value * avp_value);
+
+/* For Time AVPs, map with time_t value directly */
+int fd_dictfct_Time_encode(void * data, union avp_value * avp_value);
+int fd_dictfct_Time_interpret(union avp_value * avp_value, void * interpreted);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Time_dump, union avp_value * avp_value);
+
+
+/* For string AVP, the following type_check function provides simple basic check for specific characters presence, e.g. use "@." for trivial email address check */
+int fd_dictfct_CharInOS_check(void * data, union avp_value * val, char ** error_msg);
+
+
+/****/
+
+/***
+ * API usage :
+
+- fd_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 = fd_dict_new ( dict, DICT_TYPE, &mytypedata, NULL, &mytype );
+ }
+
+- fd_dict_search:
+ Sample code:
+ {
+ int ret;
+ struct dict_object * address_type;
+ ret = fd_dict_search ( dict, 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. freeDiameter allows constants 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 below */
+ ENUMVAL_BY_NAME, /* This cannot be used for researches */
+ ENUMVAL_BY_VALUE /* This cannot be used for researches */
+};
+
+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 :
+
+- fd_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 = fd_dict_new ( dict, DICT_TYPE, &type_boolean_data, NULL, &type_boolean );
+ ret = fd_dict_new ( dict, DICT_ENUMVAL, &boolean_false, type_boolean, NULL );
+ ret = fd_dict_new ( dict, DICT_ENUMVAL, &boolean_true , type_boolean, NULL );
+
+ }
+
+- fd_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 = fd_dict_search ( dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &boolean_by_value, &value_found, ENOENT);
+ }
+
+ - fd_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 = fd_dict_search ( dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &boolean_by_value, &value_found, ENOENT);
+ ret = fd_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
+
+/* For dumping flags and values */
+#define DUMP_AVPFL_str "%c%c%s%s%s%s%s%s"
+#define DUMP_AVPFL_val(_val) (_val & AVP_FLAG_VENDOR)?'V':'-' , (_val & AVP_FLAG_MANDATORY)?'M':'-', \
+ (_val & AVP_FLAG_RESERVED3)?"3":"", (_val & AVP_FLAG_RESERVED4)?"4":"", \
+ (_val & AVP_FLAG_RESERVED5)?"5":"", (_val & AVP_FLAG_RESERVED6)?"6":"", (_val & AVP_FLAG_RESERVED7)?"7":"", (_val & AVP_FLAG_RESERVED8)?"8":""
+
+/* 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 char *, vendor is always 0 */
+ AVP_BY_NAME_ALL_VENDORS,/* "what" points to a string. Might be quite slow... */
+ AVP_BY_STRUCT, /* "what" points to a struct dict_avp_request_ex (see below) */
+
+ /* kept for backward compatibility, better use AVP_BY_STRUCT above instead */
+ AVP_BY_CODE_AND_VENDOR, /* "what" points to a struct dict_avp_request (see below), where avp_vendor and avp_code are set */
+ AVP_BY_NAME_AND_VENDOR /* "what" points to a struct dict_avp_request (see below), where avp_vendor and avp_name are set */
+};
+
+/* Struct used for some researchs */
+struct dict_avp_request_ex {
+ struct {
+ /* Only one of the following fields must be set. */
+ struct dict_object * vendor; /* most efficient if already known, set to NULL to ignore */
+ vendor_id_t vendor_id; /* set to 0 to ignore -- prefer AVP_BY_CODE or AVP_BY_NAME for vendor 0 */
+ const char * vendor_name; /* set to NULL to ignore */
+ } avp_vendor;
+
+ struct {
+ /* Only one of the following fields must be set */
+ avp_code_t avp_code; /* set to 0 to ignore */
+ const char * avp_name; /* set to NULL to ignore */
+ } avp_data;
+};
+
+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.
+
+- fd_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 = fd_dict_new ( dict, DICT_AVP, &user_name_data, NULL, &user_name_avp );
+
+ -- Create an AVP with a derived type --
+ ret = fd_dict_search ( dict, DICT_TYPE, TYPE_BY_NAME, "Boolean", &boolean_type, ENOENT);
+ ret = fd_dict_new ( dict, DICT_AVP, &sample_boolean_data , boolean_type, &sample_boolean_avp );
+
+ }
+
+- fd_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 = fd_dict_search ( dict, DICT_AVP, AVP_BY_NAME, "User-Name", &avp_username, ENOENT);
+
+ ret = fd_dict_search ( dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &avpvendorboolean, &avp_sampleboolean, ENOENT);
+
+ -- this would also work, but be slower, because it has to search all vendor dictionaries --
+ ret = fd_dict_search ( dict, DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Sample-Boolean", &avp_sampleboolean, ENOENT);
+
+ }
+
+ - fd_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 = fd_dict_search ( dict, DICT_AVP, AVP_BY_NAME, "User-Name", &avp_username, ENOENT);
+ ret = fd_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
+
+/* For dumping flags and values */
+#define DUMP_CMDFL_str "%c%c%c%c%s%s%s%s"
+#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':'-', \
+ (_val & CMD_FLAG_RESERVED5)?"5":"", (_val & CMD_FLAG_RESERVED6)?"6":"", (_val & CMD_FLAG_RESERVED7)?"7":"", (_val & CMD_FLAG_RESERVED8)?"8":""
+
+/* 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 char * */
+ 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.
+
+- fd_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 = fd_dict_new (dict, 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 = fd_dict_new ( dict, DICT_COMMAND, &ce_data, NULL, &cea );
+ }
+
+- fd_dict_search:
+ Sample code to look for a command
+ {
+ int ret;
+ struct dict_object * cer, * cea;
+ command_code_t code = 257;
+ ret = fd_dict_search ( dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer, ENOENT);
+ ret = fd_dict_search ( dict, DICT_COMMAND, CMD_BY_CODE_R, &code, &cer, ENOENT);
+ }
+
+ - fd_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 = fd_dict_search ( dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer, ENOENT);
+ ret = fd_dict_search ( dict, DICT_COMMAND, CMD_ANSWER, cer, &cea, ENOENT);
+ ret = fd_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 below. 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).
+
+- fd_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 = fd_dict_new ( dict, DICT_AVP, &proxy_info_data, NULL, &proxy_info_avp );
+
+ -- Create the first child AVP.
+ ret = fd_dict_new ( dict, DICT_TYPE, &di_type_data, NULL, &diameteridentity_type );
+ ret = fd_dict_new ( dict, DICT_AVP, &proxy_host_data, diameteridentity_type, &proxy_host_avp );
+
+ -- Create the other child AVP
+ ret = fd_dict_new ( dict, 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 = fd_dict_new ( dict, DICT_RULE, &rule_data, proxy_info_avp, NULL );
+
+ rule_data.rule_avp = proxy_state_avp;
+ ret = fd_dict_new ( dict, DICT_RULE, &rule_data, proxy_info_avp, NULL );
+}
+
+- fd_dict_search and fd_dict_getval are similar to previous examples.
+
+*/
+
+/* Define some hard-coded values */
+/* Application */
+#define AI_RELAY 0xffffffff
+
+/* 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_USER_NAME 1
+#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
+#define ACV_ISI_NO_INBAND_SECURITY 0
+#define ACV_ISI_TLS 1
+
+/* Error codes from Base protocol
+(reference: http://www.iana.org/assignments/aaa-parameters/aaa-parameters.xml#aaa-parameters-4)
+Note that currently, rfc3588bis-26 has some different values for some of these
+*/
+#define ER_DIAMETER_MULTI_ROUND_AUTH 1001
+
+#define ER_DIAMETER_SUCCESS 2001
+#define ER_DIAMETER_LIMITED_SUCCESS 2002
+
+#define ER_DIAMETER_COMMAND_UNSUPPORTED 3001 /* 5019 ? */
+#define ER_DIAMETER_UNABLE_TO_DELIVER 3002
+#define ER_DIAMETER_REALM_NOT_SERVED 3003
+#define ER_DIAMETER_TOO_BUSY 3004
+#define ER_DIAMETER_LOOP_DETECTED 3005
+#define ER_DIAMETER_REDIRECT_INDICATION 3006
+#define ER_DIAMETER_APPLICATION_UNSUPPORTED 3007
+#define ER_DIAMETER_INVALID_HDR_BITS 3008 /* 5020 ? */
+#define ER_DIAMETER_INVALID_AVP_BITS 3009 /* 5021 ? */
+#define ER_DIAMETER_UNKNOWN_PEER 3010 /* 5018 ? */
+
+#define ER_DIAMETER_AUTHENTICATION_REJECTED 4001
+#define ER_DIAMETER_OUT_OF_SPACE 4002
+#define ER_ELECTION_LOST 4003
+
+#define ER_DIAMETER_AVP_UNSUPPORTED 5001
+#define ER_DIAMETER_UNKNOWN_SESSION_ID 5002
+#define ER_DIAMETER_AUTHORIZATION_REJECTED 5003
+#define ER_DIAMETER_INVALID_AVP_VALUE 5004
+#define ER_DIAMETER_MISSING_AVP 5005
+#define ER_DIAMETER_RESOURCES_EXCEEDED 5006
+#define ER_DIAMETER_CONTRADICTING_AVPS 5007
+#define ER_DIAMETER_AVP_NOT_ALLOWED 5008
+#define ER_DIAMETER_AVP_OCCURS_TOO_MANY_TIMES 5009
+#define ER_DIAMETER_NO_COMMON_APPLICATION 5010
+#define ER_DIAMETER_UNSUPPORTED_VERSION 5011
+#define ER_DIAMETER_UNABLE_TO_COMPLY 5012
+#define ER_DIAMETER_INVALID_BIT_IN_HEADER 5013 /* 3011 ? */
+#define ER_DIAMETER_INVALID_AVP_LENGTH 5014
+#define ER_DIAMETER_INVALID_MESSAGE_LENGTH 5015 /* 3012 ? */
+#define ER_DIAMETER_INVALID_AVP_BIT_COMBO 5016 /* deprecated? */
+#define ER_DIAMETER_NO_COMMON_SECURITY 5017
+
+
+/*============================================================*/
+/* SESSIONS */
+/*============================================================*/
+
+/* Modules that want to associate a state with a Session-Id must first register a handler of this type */
+struct session_handler;
+
+/* This opaque structure represents a session associated with a Session-Id */
+struct session;
+
+/* The state information that a module associate with a session -- each module defines its own data format */
+struct sess_state; /* declare this in your own extension */
+
+typedef DECLARE_FD_DUMP_PROTOTYPE((*session_state_dump), struct sess_state * st);
+
+/* The following function must be called to activate the session expiry mechanism */
+int fd_sess_start(void);
+
+/*
+ * FUNCTION: fd_sess_handler_create
+ *
+ * PARAMETERS:
+ * handler : location where the new handler must be stored.
+ * cleanup : a callback function that must be called when the session with associated data is destroyed.
+ * dumper : if not NULL, will be called during fd_sess_dump to display the data associated with a session. NULL otherwise.
+ * opaque : A pointer that is passed to the cleanup callback -- the content is never examined by the framework.
+ *
+ * DESCRIPTION:
+ * Create a new session handler. This is needed by a module to associate a state with a session object.
+ * The cleanup handler is called when the session timeout expires, or fd_sess_destroy is called. It must free
+ * the state associated with the session, and eventually trig other actions (send a STR, ...).
+ *
+ * RETURN VALUE:
+ * 0 : The new handler has been created.
+ * EINVAL : A parameter is invalid.
+ * ENOMEM : Not enough memory to complete the operation
+ */
+int fd_sess_handler_create ( struct session_handler ** handler, void (*cleanup)(struct sess_state * state, os0_t sid, void * opaque), session_state_dump dumper, void * opaque );
+
+
+/*
+ * FUNCTION: fd_sess_handler_destroy
+ *
+ * PARAMETERS:
+ * handler : location of an handler created by fd_sess_handler_create.
+ * opaque : the opaque pointer registered with the callback is restored here (if ! NULL).
+ *
+ * DESCRIPTION:
+ * This destroys a session handler (typically called when an application is shutting down).
+ * If sessions states are registered with this handler, the cleanup callback is called on them.
+ *
+ * RETURN VALUE:
+ * 0 : The handler was destroyed.
+ * EINVAL : A parameter is invalid.
+ * ENOMEM : Not enough memory to complete the operation
+ */
+int fd_sess_handler_destroy ( struct session_handler ** handler, void **opaque );
+
+
+
+/*
+ * FUNCTION: fd_sess_new
+ *
+ * PARAMETERS:
+ * session : The location where the session object will be created upon success.
+ * diamid : a Diameter Identity, or NULL.
+ * diamidlen : if diamid is \0-terminated, this can be 0. Otherwise, the length of diamid.
+ * opt : Additional string, or NULL. Usage is described below.
+ * optlen : if opt is \0-terminated, this can be 0. Otherwise, the length of opt.
+ *
+ * DESCRIPTION:
+ * Create a new session object. The Session-Id string associated with this session is generated as follow:
+ * If diamId parameter is provided, the string is created according to the RFC: <diamId>;<high32>;<low32>[;opt] where
+ * diamId is a Diameter Identity.
+ * high32 and low32 are the parts of a monotonic 64 bits counter initialized to (time, 0) at startup.
+ * opt is an optional string that can be concatenated to the identifier.
+ * If diamId is NULL, the string is exactly the content of opt.
+ *
+ * RETURN VALUE:
+ * 0 : The session is created, the initial msg refcount is 1.
+ * EINVAL : A parameter is invalid.
+ * EALREADY : A session with the same name already exists (returned in *session), the msg refcount is increased.
+ * ENOMEM : Not enough memory to complete the operation
+ */
+int fd_sess_new ( struct session ** session, DiamId_t diamid, size_t diamidlen, uint8_t * opt, size_t optlen );
+
+/*
+ * FUNCTION: fd_sess_fromsid
+ *
+ * PARAMETERS:
+ * sid : pointer to a string containing a Session-Id (should be UTF-8).
+ * len : length of the sid string (which does not need to be '\0'-terminated)
+ * session : On success, pointer to the session object created / retrieved.
+ * isnew : if not NULL, set to 1 on return if the session object has been created, 0 if it was simply retrieved.
+ *
+ * DESCRIPTION:
+ * Retrieve a session object from a Session-Id string. In case no session object was previously existing with this
+ * id, a new object is silently created (equivalent to fd_sess_new with flag SESSION_NEW_FULL).
+ *
+ * RETURN VALUE:
+ * 0 : The session parameter has been updated.
+ * EINVAL : A parameter is invalid.
+ * ENOMEM : Not enough memory to complete the operation
+ */
+int fd_sess_fromsid ( uint8_t * sid, size_t len, struct session ** session, int * isnew);
+
+/* only use the following in specific situations, e.g. app_radgw extension. They are normally handled by the framework only */
+int fd_sess_fromsid_msg ( uint8_t * sid, size_t len, struct session ** session, int * isnew);
+int fd_sess_ref_msg ( struct session * session );
+
+/*
+ * FUNCTION: fd_sess_getsid
+ *
+ * PARAMETERS:
+ * session : Pointer to a session object.
+ * sid : On success, the location of the sid is stored here.
+ *
+ * DESCRIPTION:
+ * Retrieve the session identifier (Session-Id) corresponding to a session object.
+ * The returned sid is a \0-terminated binary string which might be UTF-8 (but there is no guarantee in the framework).
+ * It may be used for example to set the value of an AVP.
+ * Note that the sid string is not copied, just its reference... do not free it!
+ *
+ * RETURN VALUE:
+ * 0 : The sid & len parameters have been updated.
+ * EINVAL : A parameter is invalid.
+ */
+int fd_sess_getsid ( struct session * session, os0_t * sid, size_t * sidlen );
+
+/*
+ * FUNCTION: fd_sess_settimeout
+ *
+ * PARAMETERS:
+ * session : The session for which to set the timeout.
+ * timeout : The date when the session times out.
+ *
+ * DESCRIPTION:
+ * Set the lifetime for a given session object. This function may be
+ * called several times on the same object to update the timeout value.
+ * When the timeout date is reached, the cleanup handler of each
+ * module that registered data with this session is called, then the
+ * session is cleared.
+ *
+ * There is a possible race condition between cleanup of the session
+ * and use of its data; applications should ensure that they are not
+ * using data from a session that is about to expire / expired.
+ *
+ * RETURN VALUE:
+ * 0 : The session timeout has been updated.
+ * EINVAL : A parameter is invalid.
+ */
+int fd_sess_settimeout( struct session * session, const struct timespec * timeout );
+
+/*
+ * FUNCTION: fd_sess_destroy
+ *
+ * PARAMETERS:
+ * session : Pointer to a session object.
+ *
+ * DESCRIPTION:
+ * Destroys all associated states of a session, if any.
+ * Equivalent to a session timeout expired, but the effect is immediate.
+ * The session itself is marked as deleted, and will be freed when it is not referenced
+ * by any message anymore.
+ *
+ * RETURN VALUE:
+ * 0 : The session no longer exists.
+ * EINVAL : A parameter is invalid.
+ */
+int fd_sess_destroy ( struct session ** session );
+
+/*
+ * FUNCTION: fd_sess_reclaim
+ *
+ * PARAMETERS:
+ * session : Pointer to a session object.
+ *
+ * DESCRIPTION:
+ * Equivalent to fd_sess_destroy, only if no session_state is associated with the session.
+ * Otherwise, this function has no effect (except that it sets *session to NULL).
+ *
+ * RETURN VALUE:
+ * 0 : The session was reclaimed.
+ * EINVAL : A parameter is invalid.
+ */
+int fd_sess_reclaim ( struct session ** session );
+
+
+
+
+/*
+ * FUNCTION: fd_sess_state_store
+ *
+ * PARAMETERS:
+ * handler : The handler with which the state is registered.
+ * session : The session object with which the state is registered.
+ * state : An application state (opaque data) to store with the session.
+ *
+ * DESCRIPTION:
+ * Stores an application state with a session. This state can later be retrieved
+ * with fd_sess_state_retrieve, or implicitly in the cleanup handler when the session
+ * is destroyed.
+ *
+ * RETURN VALUE:
+ * 0 : The state has been stored.
+ * EINVAL : A parameter is invalid.
+ * EALREADY : Data was already associated with this session and client.
+ * ENOMEM : Not enough memory to complete the operation
+ */
+int fd_sess_state_store ( struct session_handler * handler, struct session * session, struct sess_state ** state );
+
+/*
+ * FUNCTION: fd_sess_state_retrieve
+ *
+ * PARAMETERS:
+ * handler : The handler with which the state was registered.
+ * session : The session object with which the state was registered.
+ * state : Location where the state must be saved if it is found.
+ *
+ * DESCRIPTION:
+ * Retrieves a state saved by fd_sess_state_store.
+ * After this function has been called, the state is no longer associated with
+ * the session. A new call to fd_sess_state_store must be performed in order to
+ * store again the data with the session.
+ *
+ * RETURN VALUE:
+ * 0 : *state is updated (NULL or points to the state if it was found).
+ * EINVAL : A parameter is invalid.
+ */
+int fd_sess_state_retrieve ( struct session_handler * handler, struct session * session, struct sess_state ** state );
+
+
+/* For debug */
+DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump, struct session * session, int with_states);
+DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump_hdl, struct session_handler * handler);
+
+/* For statistics / monitoring: get the number of struct session in memory */
+int fd_sess_getcount(uint32_t *cnt);
+
+/*============================================================*/
+/* ROUTING */
+/*============================================================*/
+
+/* The following functions are helpers for the routing module.
+ The routing data is stored in the message itself. */
+
+/* Structure that contains the routing data for a message */
+struct rt_data;
+
+/* Following functions are helpers to create the routing data of a message */
+int fd_rtd_init(struct rt_data ** rtd);
+void fd_rtd_free(struct rt_data ** rtd);
+
+/* Add a peer to the candidates list. */
+int fd_rtd_candidate_add(struct rt_data * rtd, DiamId_t peerid, size_t peeridlen, DiamId_t realm, size_t realmlen);
+
+/* Remove a peer from the candidates (if it is found). The search is case-insensitive. */
+void fd_rtd_candidate_del(struct rt_data * rtd, uint8_t * id, size_t idsz);
+
+/* Extract the list of valid candidates, and initialize their scores to 0 */
+void fd_rtd_candidate_extract(struct rt_data * rtd, struct fd_list ** candidates, int ini_score);
+
+/* If a peer returned a protocol error for this message, save it so that we don't try to send it there again. Optionally retrieve the current list of candidates. */
+int fd_rtd_error_add(struct rt_data * rtd, DiamId_t sentto, size_t senttolen, uint8_t * origin, size_t originsz, uint32_t rcode, struct fd_list ** candidates, int * sendingattemtps);
+
+/* Only retrieve the number of times this message has been processed by the routing-out mechanism (i.e. number of times it was failed over) */
+int fd_rtd_get_nb_attempts(struct rt_data * rtd, int * sendingattemtps);
+
+/* The extracted list items have the following structure: */
+struct rtd_candidate {
+ struct fd_list chain; /* link in the list returned by the previous fcts */
+ DiamId_t diamid; /* the diameter Id of the peer */
+ size_t diamidlen; /* cached size of the diamid string */
+ DiamId_t realm; /* the diameter realm of the peer */
+ size_t realmlen; /* cached size of realm */
+ int score; /* the current routing score for this peer, see fd_rt_out_register definition for details */
+};
+
+/* Reorder the list of peers by score */
+int fd_rtd_candidate_reorder(struct fd_list * candidates);
+
+/* Note : it is fine for a callback to add a new entry in the candidates list after the list has been extracted. The diamid must then be malloc'd. */
+/* Beware that this could lead to routing loops */
+
+/*============================================================*/
+/* 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.
+ * Example:
+ * 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 below */
+#define AVPFL_SET_BLANK_VALUE 0x01 /* When creating an AVP, initialize its value to a blank area */
+#define AVPFL_SET_RAWDATA_FROM_AVP 0x02 /* When creating an AVP, initialize its rawdata area from an existing AVP -- it is only blank padding (for error reporting) */
+#define AVPFL_MAX AVPFL_SET_RAWDATA_FROM_AVP /* The biggest valid flag value */
+
+#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_ANSW_NOSID 0x04 /* When creating an answer message, do not add the Session-Id even if present in request */
+#define MSGFL_ANSW_NOPROXYINFO 0x08 /* When creating an answer message, do not add the Proxy-Info AVPs presents in request */
+#define MSGFL_MAX MSGFL_ANSW_NOPROXYINFO /* 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 if flags are used.
+ * flags : Flags to use in creation (AVPFL_*, see above).
+ * avp : Upon success, pointer to the new avp is stored here. It points to reference AVP upon function call when flags are used.
+ *
+ * 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 );
+int fd_msg_new_appl ( struct dict_object * model, struct dict_object * appl, 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)
+ * : See other MSGFL_ANSW_* definition above for other flags.
+ *
+ * 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.
+ * Note that the added AVP will be freed at the same time as the object it is added to,
+ * so it should not be freed after the call to this function.
+ *
+ * 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:
+ * see definition of DECLARE_FD_DUMP_PROTOTYPE,
+ * obj : A msg or avp object to dump.
+ * dict : the dictionary to use if parsing is requested (optional)
+ * force_parsing: by default these functions do not parse the object but dump hexa values in that case.
+ * use !0 to force parsing. If parsing fails, the hexa dump is still provided.
+ * recurse : allow the function to go through the children objects if any to dump more information. might require parsing.
+ *
+ * DESCRIPTION:
+ * These functions dump the content of a message or avp into a buffer
+ * either recursively or only the object itself.
+ *
+ * RETURN VALUE:
+ * - see DECLARE_FD_DUMP_PROTOTYPE,
+ */
+/* one-line dump with only short information */
+DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_summary, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse );
+/* one-line dump with all the contents of the message */
+DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_full, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse );
+/* multi-line human-readable dump similar to wireshark output */
+DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_treeview, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse );
+
+
+/*********************************************/
+/* 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 request message
+ * anscb : the callback to associate with the message
+ * data : the data to pass to the callback
+ * expirecb : the expiration callback to associate with the message
+ * timeout : (optional, use NULL if no timeout) a timeout associated with calling the cb.
+ *
+ * DESCRIPTION:
+ * Associate or retrieve callbacks with an 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, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout );
+int fd_msg_anscb_get( struct msg * msg, void (**anscb)(void *, struct msg **), void (**expirecb)(void *, DiamId_t, size_t, struct msg **), void ** data );
+int fd_msg_anscb_reset(struct msg * msg, int clear_anscb, int clear_expirecb);
+struct timespec *fd_msg_anscb_gettimeout( struct msg * msg ); /* returns NULL or a valid non-0 timespec */
+
+/*
+ * 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 rt_data * rtd );
+int fd_msg_rt_get ( struct msg * msg, struct rt_data ** rtd );
+
+/*
+ * 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,len : The diameter id of the peer from which this message was received.
+ * dict : a dictionary with definition of Route-Record AVP (for fd_msg_source_setrr)
+ *
+ * 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, DiamId_t diamid, size_t diamidlen );
+int fd_msg_source_setrr( struct msg * msg, DiamId_t diamid, size_t diamidlen, struct dictionary * dict );
+int fd_msg_source_get( struct msg * msg, DiamId_t *diamid, size_t * diamidlen );
+
+/*
+ * 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 );
+
+
+/*
+ * FUNCTION: fd_msg_sess_get
+ *
+ * PARAMETERS:
+ * dict : the dictionary that contains the Session-Id AVP definition
+ * msg : A valid message.
+ * session : Location to store the session pointer when retrieved.
+ * isnew : Indicates if the session has been created.
+ *
+ * DESCRIPTION:
+ * This function retrieves or creates the session object corresponding to a message.
+ * If the message does not contain a Session-Id AVP, *session == NULL on return.
+ * Note that the Session-Id AVP must never be modified after created in a message.
+ *
+ * RETURN VALUE:
+ * 0 : success
+ * !0 : standard error code.
+ */
+int fd_msg_sess_get(struct dictionary * dict, struct msg * msg, struct session ** session, int * isnew);
+
+/* This one is used by the libfdcore, you should use fd_msg_new_session rather than fd_sess_new, when possible */
+int fd_msg_sess_set(struct msg * msg, struct session * session);
+
+
+/* Helper for the hooks mechanism, for use from libfdcore */
+struct fd_msg_pmdl {
+ struct fd_list sentinel; /* if the sentinel.o field is NULL, the structure is not initialized. Otherwise it points to the cleanup function in libfdcore. */
+ pthread_mutex_t lock;
+};
+struct fd_msg_pmdl * fd_msg_pmdl_get(struct msg * msg);
+
+
+/***************************************/
+/* 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, uint8_t ** 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 ( uint8_t ** buffer, size_t buflen, struct msg ** msg );
+
+/* Parsing Error Information structure */
+struct fd_pei {
+ char * pei_errcode; /* name of the error code to use */
+ struct avp * pei_avp; /* pointer to invalid (in original message) or missing AVP (to be freed) */
+ int pei_avp_free; /* Set to 1 if the pei_avp must be freed */
+ char * pei_message; /* Overwrite default message if needed */
+ int pei_protoerr; /* do we set the 'E' bit in the error message ? */
+};
+
+/*
+ * 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.
+ * error_info : If not NULL, will contain the detail about error upon return. May be used to generate an error reply.
+ *
+ * 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 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, struct fd_pei * error_info );
+
+/*
+ * FUNCTION: fd_msg_parse_rules
+ *
+ * PARAMETERS:
+ * object : A msg or grouped avp object that must be verified.
+ * dict : The dictionary containing the rules definitions.
+ * error_info : If not NULL, the first problem information will be saved here.
+ *
+ * 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 fd_pei * error_info);
+
+
+
+/*
+ * 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 );
+
+
+/*============================================================*/
+/* DISPATCH */
+/*============================================================*/
+
+/* Dispatch module (passing incoming messages to extensions registered callbacks)
+ * is split between the library and the daemon.
+ *
+ * The library provides the support for associating dispatch callbacks with
+ * dictionary objects.
+ *
+ * The daemon is responsible for calling the callbacks for a message when appropriate.
+ *
+ *
+ * The dispatch module has two main roles:
+ * - help determine if a message can be handled locally (during the routing step)
+ * This decision involves only the application-id of the message.
+ * - pass the message to the callback(s) that will handle it (during the dispatch step)
+ *
+ * The first role is handled by the daemon.
+ *
+ * About the second, these are the possibilities for registering a dispatch callback:
+ *
+ * -> For All messages.
+ * This callback is called for all messages that are handled locally. This should be used only
+ * for debug purpose.
+ *
+ * -> by AVP value (constants only).
+ * This callback will be called when a message is received and contains an AVP with a specified enumerated value.
+ *
+ * -> by AVP.
+ * This callback will be called when the received message contains a certain AVP.
+ *
+ * -> by command-code.
+ * This callback will be called when the message is a specific command (and 'R' flag).
+ *
+ * -> by application.
+ * This callback will be called when the message has a specific application-id.
+ *
+ * ( by vendor: would this be useful? it may be added later)
+ */
+enum disp_how {
+ DISP_HOW_ANY = 1, /* Any message. This should be only used for debug. */
+ DISP_HOW_APPID, /* Any message with the specified application-id */
+ DISP_HOW_CC, /* Messages of the specified command-code (request or answer). App id may be specified. */
+ DISP_HOW_AVP, /* Messages containing a specific AVP. Command-code and App id may be specified. */
+ DISP_HOW_AVP_ENUMVAL /* Messages containing a specific AVP with a specific enumerated value. Command-code and App id may be specified. */
+};
+/*
+ * Several criteria may be selected at the same time, for example command-code AND application id.
+ *
+ * If several callbacks are registered for the same object, they are called in the order they were registered.
+ * The order in which the callbacks are called is:
+ * DISP_HOW_ANY
+ * DISP_HOW_AVP_ENUMVAL & DISP_HOW_AVP
+ * DISP_HOW_CC
+ * DISP_HOW_APPID
+ */
+
+/* When a callback is registered, a "when" argument is passed in addition to the disp_how value,
+ * to specify which values the criteria must match. */
+struct disp_when {
+ struct dict_object * app;
+ struct dict_object * command;
+ struct dict_object * avp;
+ struct dict_object * value;
+};
+
+/* Note that all the dictionary objects should really belong to the same dictionary!
+ *
+ * Here is the details on this "when" argument, depending on the disp_how value.
+ *
+ * DISP_HOW_ANY.
+ * In this case, "when" must be NULL.
+ *
+ * DISP_HOW_APPID.
+ * Only the "app_id" field must be set, other fields are ignored. It points to a dictionary object of type DICT_APPLICATION.
+ *
+ * DISP_HOW_CC.
+ * The "command" field must be defined and point to a dictionary object of type DICT_COMMAND.
+ * The "app_id" may be also set. In the case it is set, it restricts the callback to be called only with this command-code and app id.
+ * The other fields are ignored.
+ *
+ * DISP_HOW_AVP.
+ * The "avp" field of the structure must be set and point to a dictionary object of type DICT_AVP.
+ * The "app_id" field may be set to restrict the messages matching to a specific app id.
+ * The "command" field may also be set to a valid DICT_COMMAND object.
+ * The content of the "value" field is ignored.
+ *
+ * DISP_HOW_AVP_ENUMVAL.
+ * All fields have the same constraints and meaning as in DISP_REG_AVP. In addition, the "value" field must be set
+ * and points to a valid DICT_ENUMVAL object.
+ *
+ * Here is a sumary of the fields: ( M : must be set; m : may be set; 0 : ignored )
+ * field: app_id command avp value
+ * APPID : M 0 0 0
+ * CC : m M 0 0
+ * AVP : m m M 0
+ * ENUMVA: m m M M
+ */
+
+enum disp_action {
+ DISP_ACT_CONT, /* The next handler should be called, unless *msg == NULL. */
+ DISP_ACT_SEND, /* The updated message must be sent. No further callback is called. */
+ DISP_ACT_ERROR /* An error must be created and sent as a reply -- not valid for callbacks, only for fd_msg_dispatch. */
+};
+/* The callbacks that are registered have the following prototype:
+ * int dispatch_callback( struct msg ** msg, struct avp * avp, struct session * session, enum disp_action * action );
+ *
+ * CALLBACK: dispatch_callback
+ *
+ * PARAMETERS:
+ * msg : the received message on function entry. may be updated to answer on return (see description)
+ * avp : for callbacks registered with DISP_HOW_AVP or DISP_HOW_AVP_ENUMVAL, direct link to the triggering AVP.
+ * session : if the message contains a Session-Id AVP, the corresponding session object, NULL otherwise.
+ * opaque : An opaque pointer that is registered along the session handler.
+ * action : upon return, this tells the daemon what to do next.
+ *
+ * DESCRIPTION:
+ * Called when a received message matchs the condition for which the callback was registered.
+ * This callback may do any kind of processing on the message, including:
+ * - create an answer for a request.
+ * - proxy a request or message, add / remove the Proxy-Info AVP, then forward the message.
+ * - update a routing table or start a connection with a new peer, then forward the message.
+ * - ...
+ *
+ * When *action == DISP_ACT_SEND on callback return, the msg pointed by *msg is passed to the routing module for sending.
+ * When *action == DISP_ACT_CONT, the next registered callback is called.
+ * When the last callback gives also DISP_ACT_CONT action value, a default handler is called. It's behavior is as follow:
+ * - if the message is an answer, it is discarded.
+ * - if the message is a request, it is passed again to the routing stack, and marked as non-local handling.
+ *
+ * RETURN VALUE:
+ * 0 : The callback executed successfully and updated *action appropriately.
+ * !0 : standard errors. In case of error, the message is discarded.
+ */
+
+/* This structure represents a handler for a registered callback, allowing its de-registration */
+struct disp_hdl;
+
+/*
+ * FUNCTION: fd_disp_register
+ *
+ * PARAMETERS:
+ * cb : The callback function to register (see dispatch_callback description above).
+ * how : How the callback must be registered.
+ * when : Values that must match, depending on the how argument.
+ * opaque : A pointer that is passed back to the handler. The content is not interpreted by the framework.
+ * handle : On success, a handler to the registered callback is stored here if not NULL.
+ * This handler can be used to unregister the cb.
+ *
+ * DESCRIPTION:
+ * Register a new callback to handle messages delivered locally.
+ *
+ * RETURN VALUE:
+ * 0 : The callback is registered.
+ * EINVAL : A parameter is invalid.
+ * ENOMEM : Not enough memory to complete the operation
+ */
+int fd_disp_register ( int (*cb)( struct msg **, struct avp *, struct session *, void *, enum disp_action *),
+ enum disp_how how, struct disp_when * when, void * opaque, struct disp_hdl ** handle );
+
+/*
+ * FUNCTION: fd_disp_unregister
+ *
+ * PARAMETERS:
+ * handle : Location of the handle of the callback that must be unregistered.
+ * opaque : If not NULL, the opaque data that was registered is restored here.
+ *
+ * DESCRIPTION:
+ * Removes a callback previously registered by fd_disp_register.
+ *
+ * RETURN VALUE:
+ * 0 : The callback is unregistered.
+ * EINVAL : A parameter is invalid.
+ */
+int fd_disp_unregister ( struct disp_hdl ** handle, void ** opaque );
+
+/* Destroy all handlers */
+void fd_disp_unregister_all ( void );
+
+/*
+ * FUNCTION: fd_msg_dispatch
+ *
+ * PARAMETERS:
+ * msg : A msg object that have already been fd_msg_parse_dict.
+ * session : The session corresponding to this object, if any.
+ * action : Upon return, the action that must be taken on the message
+ * error_code : Upon return with action == DISP_ACT_ERROR, contains the error (such as "DIAMETER_UNABLE_TO_COMPLY")
+ * drop_reason : if set on return, the message must be freed for this reason.
+ * drop_msg : if drop_reason is set, this points to the message to be freed while *msg is NULL.
+ *
+ * DESCRIPTION:
+ * Call all handlers registered for a given message.
+ * The session must have already been resolved on entry.
+ * The msg pointed may be updated during this process.
+ * Upon return, the action parameter points to what must be done next.
+ *
+ * RETURN VALUE:
+ * 0 : Success.
+ * EINVAL : A parameter is invalid.
+ * (other errors)
+ */
+int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, char ** error_code, char ** drop_reason, struct msg ** drop_msg );
+
+
+
+/*============================================================*/
+/* QUEUES */
+/*============================================================*/
+
+/* Management of FIFO queues of elements */
+
+/* A queue is an opaque object */
+struct fifo;
+
+/*
+ * FUNCTION: fd_fifo_new
+ *
+ * PARAMETERS:
+ * queue : Upon success, a pointer to the new queue is saved here.
+ * max : max number of items in the queue. Above this number, adding a new item becomes a
+ * blocking operation. Use 0 to disable this maximum.
+ *
+ * DESCRIPTION:
+ * Create a new empty queue.
+ *
+ * RETURN VALUE :
+ * 0 : The queue has been initialized successfully.
+ * EINVAL : The parameter is invalid.
+ * ENOMEM : Not enough memory to complete the creation.
+ */
+int fd_fifo_new ( struct fifo ** queue, int max );
+
+/*
+ * FUNCTION: fd_fifo_del
+ *
+ * PARAMETERS:
+ * queue : Pointer to an empty queue to delete.
+ *
+ * DESCRIPTION:
+ * Destroys a queue. This is only possible if no thread is waiting for an element,
+ * and the queue is empty.
+ *
+ * RETURN VALUE:
+ * 0 : The queue has been destroyed successfully.
+ * EINVAL : The parameter is invalid.
+ */
+int fd_fifo_del ( struct fifo ** queue );
+
+/*
+ * FUNCTION: fd_fifo_move
+ *
+ * PARAMETERS:
+ * oldq : Location of a FIFO that is to be emptied.
+ * newq : A FIFO that will receive the old data.
+ * loc_update : if non NULL, a place to store the pointer to new FIFO atomically with the move.
+ *
+ * DESCRIPTION:
+ * Empties a queue and move its content to another one atomically.
+ *
+ * RETURN VALUE:
+ * 0 : The queue has been destroyed successfully.
+ * EINVAL : A parameter is invalid.
+ */
+int fd_fifo_move ( struct fifo * oldq, struct fifo * newq, struct fifo ** loc_update );
+
+/*
+ * FUNCTION: fd_fifo_getstats
+ *
+ * PARAMETERS:
+ * queue : The queue from which to retrieve the information.
+ * current_count : How many items in the queue at the time of execution. This changes each time an item is pushed or poped.
+ * limit_count : The maximum number of items allowed in this queue. This is specified during queue creation.
+ * highest_count : The maximum number of items this queue has contained. This enables to see if limit_count count was reached.
+ * total_count : the total number of items that went through the queue (already pop'd). Always increasing.
+ * total : Cumulated time all items spent in this queue, including blocking time (always growing, use deltas for monitoring)
+ * blocking : Cumulated time threads trying to post new items were blocked (queue full).
+ * last : For the last element retrieved from the queue, how long it take between posting (including blocking) and poping
+ *
+ * DESCRIPTION:
+ * Retrieve the timing information associated with a queue, for monitoring purpose.
+ *
+ * RETURN VALUE:
+ * 0 : The statistics have been updated.
+ * EINVAL : A parameter is invalid.
+ */
+int fd_fifo_getstats( struct fifo * queue, int * current_count, int * limit_count, int * highest_count, long long * total_count,
+ struct timespec * total, struct timespec * blocking, struct timespec * last);
+
+/*
+ * FUNCTION: fd_fifo_length
+ *
+ * PARAMETERS:
+ * queue : The queue from which to retrieve the number of elements.
+ *
+ * DESCRIPTION:
+ * Retrieve the number of elements in a queue, without error checking.
+ *
+ * RETURN VALUE:
+ * The number of items currently queued.
+ */
+int fd_fifo_length ( struct fifo * queue );
+
+/*
+ * FUNCTION: fd_fifo_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 elements 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 should 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 continues 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_fifo_post or fd_fifo_get. Their operation should be quick.
+ *
+ * RETURN VALUE:
+ * 0 : The thresholds have been set
+ * EINVAL : A parameter is invalid.
+ */
+int fd_fifo_setthrhd ( struct fifo * queue, void * data, uint16_t high, void (*h_cb)(struct fifo *, void **), uint16_t low, void (*l_cb)(struct fifo *, void **) );
+
+/*
+ * FUNCTION: fd_fifo_post
+ *
+ * PARAMETERS:
+ * queue : The queue in which the element must be posted.
+ * item : The element that is put in the queue.
+ *
+ * DESCRIPTION:
+ * An element is added in a queue. Elements are retrieved from the queue in FIFO order
+ * with the fd_fifo_get, fd_fifo_tryget, or fd_fifo_timedget functions.
+ *
+ * RETURN VALUE:
+ * 0 : The element is queued.
+ * EINVAL : A parameter is invalid.
+ * ENOMEM : Not enough memory to complete the operation.
+ */
+int fd_fifo_post_int ( struct fifo * queue, void ** item );
+#define fd_fifo_post(queue, item) \
+ fd_fifo_post_int((queue), (void *)(item))
+
+/* Similar function but does not block. It can cause the number of items in the queue to exceed the maximum set. Do not use for normal operation,
+only for failure recovery for example. */
+int fd_fifo_post_noblock( struct fifo * queue, void ** item );
+
+/*
+ * FUNCTION: fd_fifo_get
+ *
+ * PARAMETERS:
+ * queue : The queue from which the first element must be retrieved.
+ * item : On return, the first element of the queue is stored here.
+ *
+ * DESCRIPTION:
+ * This function retrieves the first element from a queue. If the queue is empty, the function will block the
+ * thread until a new element is posted to the queue, or until the thread is canceled (in which case the
+ * function does not return).
+ *
+ * RETURN VALUE:
+ * 0 : A new element has been retrieved.
+ * EINVAL : A parameter is invalid.
+ */
+int fd_fifo_get_int ( struct fifo * queue, void ** item );
+#define fd_fifo_get(queue, item) \
+ fd_fifo_get_int((queue), (void *)(item))
+
+/*
+ * FUNCTION: fd_fifo_tryget
+ *
+ * PARAMETERS:
+ * queue : The queue from which the element must be retrieved.
+ * item : On return, the first element of the queue is stored here.
+ *
+ * DESCRIPTION:
+ * This function is similar to fd_fifo_get, except that it will not block if
+ * the queue is empty, but return EWOULDBLOCK instead.
+ *
+ * RETURN VALUE:
+ * 0 : A new element has been retrieved.
+ * EINVAL : A parameter is invalid.
+ * EWOULDBLOCK : The queue was empty.
+ */
+int fd_fifo_tryget_int ( struct fifo * queue, void ** item );
+#define fd_fifo_tryget(queue, item) \
+ fd_fifo_tryget_int((queue), (void *)(item))
+
+/*
+ * FUNCTION: fd_fifo_timedget
+ *
+ * PARAMETERS:
+ * queue : The queue from which the element must be retrieved.
+ * item : On return, the element is stored here.
+ * abstime : the absolute time until which we allow waiting for an item.
+ *
+ * DESCRIPTION:
+ * This function is similar to fd_fifo_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 item has been retrieved.
+ * EINVAL : A parameter is invalid.
+ * ETIMEDOUT : The time out has passed and no item has been received.
+ */
+int fd_fifo_timedget_int ( struct fifo * queue, void ** item, const struct timespec *abstime );
+#define fd_fifo_timedget(queue, item, abstime) \
+ fd_fifo_timedget_int((queue), (void *)(item), (abstime))
+
+
+/*
+ * FUNCTION: fd_fifo_select
+ *
+ * PARAMETERS:
+ * queue : The queue to test.
+ * abstime : the absolute time until which we can block waiting for an item. If NULL, the function returns immediatly.
+ *
+ * DESCRIPTION:
+ * This function is similar to select(), it waits for data to be available in the queue
+ * until the abstime is expired.
+ * Upon function entry, even if abstime is already expired the data availability is tested.
+ *
+ * RETURN VALUE:
+ * 0 : timeout expired without available data.
+ * <0 : An error occurred (e.g., -EINVAL...)
+ * >0 : data is available. The next call to fd_fifo_get will not block.
+ */
+int fd_fifo_select ( struct fifo * queue, const struct timespec *abstime );
+
+
+
+/* Dump a fifo list and optionally its inner elements -- beware of deadlocks! */
+typedef DECLARE_FD_DUMP_PROTOTYPE((*fd_fifo_dump_item_cb), void * item); /* This function should be 1 line if possible, or use indent level. Ends with '\n' */
+DECLARE_FD_DUMP_PROTOTYPE(fd_fifo_dump, char * name, struct fifo * queue, fd_fifo_dump_item_cb dump_item);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBFDPROTO_H */
diff --git a/include/freeDiameter/version.h.in b/include/freeDiameter/version.h.in
new file mode 100644
index 0000000..9b0fa61
--- /dev/null
+++ b/include/freeDiameter/version.h.in
@@ -0,0 +1,3 @@
+/* Following variable is expended at build time based on the result of "hg id" command */
+#cmakedefine FD_PROJECT_VERSION_HG
+#define FD_PROJECT_VERSION_HG_VAL "@FD_PROJECT_VERSION_HG@"