# HG changeset patch # User Sebastien Decugis # Date 1253267647 -32400 # Node ID 3e143f047f7890a31c9de3dde11cd322100030ff # Parent e5af94b0494675763538df3dbbecd9931785f288 Backup for the week-end diff -r e5af94b04946 -r 3e143f047f78 CMakeLists.txt --- a/CMakeLists.txt Fri Sep 04 18:05:25 2009 +0900 +++ b/CMakeLists.txt Fri Sep 18 18:54:07 2009 +0900 @@ -3,6 +3,14 @@ # Name of the project, and language PROJECT("freeDiameter" C) +# Informations to display in daemon's help +SET(FD_PROJECT_NAME freeDiameter) +SET(FD_PROJECT_BINARY freeDiameterd) +SET(FD_PROJECT_VERSION_MAJOR 0) +SET(FD_PROJECT_VERSION_MINOR 1) +SET(FD_PROJECT_VERSION_REV 0) +SET(FD_PROJECT_COPYRIGHT "Copyright (c) 2008-2009, WIDE Project (www.wide.ad.jp) and NICT (www.nict.go.jp)") + # Some subfolders may have tests ENABLE_TESTING() @@ -15,11 +23,6 @@ # All source code should be POSIX 200112L compatible, but some other extensions might be used, so: ADD_DEFINITIONS(-D_GNU_SOURCE) -# Location for the include files -INCLUDE_DIRECTORIES(include) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/include) -SUBDIRS(include/freeDiameter) - # some subfolders use yacc and lex parsers SET(BISON_GENERATE_DEFINES TRUE) SET(BISON_PREFIX_OUTPUTS TRUE) @@ -32,6 +35,11 @@ # Check that flex is at least 2.5.20 to support bison-bridge # how to do the check with cmake??? +# Location for the include files +INCLUDE_DIRECTORIES(include) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/include) +SUBDIRS(include/freeDiameter) + # Location for the source code SUBDIRS(libfreeDiameter) SUBDIRS(freeDiameter) diff -r e5af94b04946 -r 3e143f047f78 cmake/Modules/FindGNUTLS.cmake --- a/cmake/Modules/FindGNUTLS.cmake Fri Sep 04 18:05:25 2009 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -# - Try to find GNU TLS library and headers -# Once done, this will define -# -# GNUTLS_FOUND - system has GNU TLS -# GNUTLS_INCLUDE_DIRS - the GNU TLS include directories -# GNUTLS_LIBRARIES - link these to use GNU TLS - -include(LibFindMacros) - -# Use pkg-config to get hints about paths -libfind_pkg_check_modules(GNUTLS_PKGCONF gnutls) - -# Include dir -find_path(GNUTLS_INCLUDE_DIR - NAMES gnutls/gnutls.h - PATHS ${GNUTLS_PKGCONF_INCLUDE_DIRS} -) - -# Finally the library itself -find_library(GNUTLS_LIBRARY - NAMES gnutls - PATHS ${GNUTLS_PKGCONF_LIBRARY_DIRS} -) - -# Set the include dir variables and the libraries and let libfind_process do the rest. -# NOTE: Singular variables for this library, plural for libraries this this lib depends on. -set(GNUTLS_PROCESS_INCLUDES GNUTLS_INCLUDE_DIR) -set(GNUTLS_PROCESS_LIBS GNUTLS_LIBRARY) -libfind_process(GNUTLS) diff -r e5af94b04946 -r 3e143f047f78 cmake/Modules/FindSCTP.cmake --- a/cmake/Modules/FindSCTP.cmake Fri Sep 04 18:05:25 2009 +0900 +++ b/cmake/Modules/FindSCTP.cmake Fri Sep 18 18:54:07 2009 +0900 @@ -5,25 +5,42 @@ # SCTP_INCLUDE_DIRS - the SCTP include directories # SCTP_LIBRARIES - link these to use SCTP -include(LibFindMacros) - -# Use pkg-config to get hints about paths (Note: not yet supported?) -# libfind_pkg_check_modules(SCTP_PKGCONF sctp) +if (SCTP_INCLUDE_DIRS) + set(SCTP_FIND_QUIETLY TRUE) +endif (SCTP_INCLUDE_DIRS) # Include dir find_path(SCTP_INCLUDE_DIR NAMES netinet/sctp.h - PATHS ${SCTP_PKGCONF_INCLUDE_DIRS} ) -# Finally the library itself +# Library find_library(SCTP_LIBRARY NAMES sctp - PATHS ${SCTP_PKGCONF_LIBRARY_DIRS} ) # Set the include dir variables and the libraries and let libfind_process do the rest. # NOTE: Singular variables for this library, plural for libraries this this lib depends on. -set(SCTP_PROCESS_INCLUDES SCTP_INCLUDE_DIR) -set(SCTP_PROCESS_LIBS SCTP_LIBRARY) -libfind_process(SCTP) +#set(SCTP_PROCESS_INCLUDES SCTP_INCLUDE_DIR) +#set(SCTP_PROCESS_LIBS SCTP_LIBRARY) +#libfind_process(SCTP) + + +# handle the QUIETLY and REQUIRED arguments and set SCTP_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SCTP DEFAULT_MSG SCTP_LIBRARY SCTP_INCLUDE_DIR) + +# If we successfully found the sctp library then add the library to the +# SCTP_LIBRARIES cmake variable otherwise set SCTP_LIBRARIES to nothing. +IF(SCTP_FOUND) + SET( SCTP_LIBRARIES ${SCTP_LIBRARY} ) +ELSE(SCTP_FOUND) + SET( SCTP_LIBRARIES ) +ENDIF(SCTP_FOUND) + + +# Lastly make it so that the SCTP_LIBRARY and SCTP_INCLUDE_DIR variables +# only show up under the advanced options in the gui cmake applications. +MARK_AS_ADVANCED( SCTP_LIBRARY SCTP_INCLUDE_DIR ) + diff -r e5af94b04946 -r 3e143f047f78 cmake/Modules/LibFindMacros.cmake --- a/cmake/Modules/LibFindMacros.cmake Fri Sep 04 18:05:25 2009 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments -# used for the current package. For this to work, the first parameter must be the -# prefix of the current package, then the prefix of the new package etc, which are -# passed to find_package. -macro (libfind_package PREFIX) - set (LIBFIND_PACKAGE_ARGS ${ARGN}) - if (${PREFIX}_FIND_QUIETLY) - set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET) - endif (${PREFIX}_FIND_QUIETLY) - if (${PREFIX}_FIND_REQUIRED) - set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED) - endif (${PREFIX}_FIND_REQUIRED) - find_package(${LIBFIND_PACKAGE_ARGS}) -endmacro (libfind_package) - -# Damn CMake developers made the UsePkgConfig system deprecated in the same release (2.6) -# where they added pkg_check_modules. Consequently I need to support both in my scripts -# to avoid those deprecated warnings. Here's a helper that does just that. -# Works identically to pkg_check_modules, except that no checks are needed prior to use. -macro (libfind_pkg_check_modules PREFIX PKGNAME) - if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) - include(UsePkgConfig) - pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS) - else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) - find_package(PkgConfig) - if (PKG_CONFIG_FOUND) - pkg_check_modules(${PREFIX} ${PKGNAME}) - endif (PKG_CONFIG_FOUND) - endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) -endmacro (libfind_pkg_check_modules) - -# Do the final processing once the paths have been detected. -# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain -# all the variables, each of which contain one include directory. -# Ditto for ${PREFIX}_PROCESS_LIBS and library files. -# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. -# Also handles errors in case library detection was required, etc. -macro (libfind_process PREFIX) - # Skip processing if already processed during this run - if (NOT ${PREFIX}_FOUND) - # Start with the assumption that the library was found - set (${PREFIX}_FOUND TRUE) - - # Process all includes and set _FOUND to false if any are missing - foreach (i ${${PREFIX}_PROCESS_INCLUDES}) - if (${i}) - set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}}) - mark_as_advanced(${i}) - else (${i}) - set (${PREFIX}_FOUND FALSE) - endif (${i}) - endforeach (i) - - # Process all libraries and set _FOUND to false if any are missing - foreach (i ${${PREFIX}_PROCESS_LIBS}) - if (${i}) - set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}}) - mark_as_advanced(${i}) - else (${i}) - set (${PREFIX}_FOUND FALSE) - endif (${i}) - endforeach (i) - - # Print message and/or exit on fatal error - if (${PREFIX}_FOUND) - if (NOT ${PREFIX}_FIND_QUIETLY) - message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") - endif (NOT ${PREFIX}_FIND_QUIETLY) - else (${PREFIX}_FOUND) - if (${PREFIX}_FIND_REQUIRED) - foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS}) - message("${i}=${${i}}") - endforeach (i) - message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.") - endif (${PREFIX}_FIND_REQUIRED) - endif (${PREFIX}_FOUND) - endif (NOT ${PREFIX}_FOUND) -endmacro (libfind_process) - -macro(libfind_library PREFIX basename) - set(TMP "") - if(MSVC80) - set(TMP -vc80) - endif(MSVC80) - if(MSVC90) - set(TMP -vc90) - endif(MSVC90) - set(${PREFIX}_LIBNAMES ${basename}${TMP}) - if(${ARGC} GREATER 2) - set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2}) - string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES}) - set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP}) - endif(${ARGC} GREATER 2) - find_library(${PREFIX}_LIBRARY - NAMES ${${PREFIX}_LIBNAMES} - PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS} - ) -endmacro(libfind_library) - diff -r e5af94b04946 -r 3e143f047f78 doc/freediameter.conf.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/freediameter.conf.sample Fri Sep 18 18:54:07 2009 +0900 @@ -0,0 +1,132 @@ +# This is a sample configuration file for freeDiameter daemon. + +############################################################## +## Peer identity and realm + +# The Diameter Identity of this daemon. +# This must be a valid FQDN that resolves to the local host. +# Default: hostname's FQDN +#LocalIdentity = "aaa.koganei.wide.ad.jp"; + +# The Diameter Realm of this daemon. +# Default: the domain part of LocalIdentity. +#LocalRealm = "wide.ad.jp"; + +############################################################## +## Transport protocol configuration + +# The port this peer is listening on for incoming connections (TCP and SCTP). +# Default: 3868 +#LocalPort = 3868; + +# The port this peer is listening on for incoming TLS connections (TCP and SCTP). +# See TLS_old_method for more information. +# Default: 3869 +#LocalSecPort = 3869; + +# Use RFC3588 method for TLS protection, where TLS is negociated after CER/CEA +# on the same port. This only affects outgoing connections. It can be overwritten +# on per peer basis. +# Default: use RFC3588bis method with separate port for TLS. +#TLS_old_method; + +# Disable use of TCP protocol (only SCTP) +# Default : TCP enabled +#No_TCP; + +# Disable use of SCTP protocol (only TCP) +# Default : SCTP enabled +#No_SCTP; +# This option has no effect if freeDiameter is compiled with DISABLE_SCTP option, +# in which case the value is forced to "SCTP disabled". + +# Prefer TCP over SCTP for establishing new connections. +# It may be overwritten per peer in peer configuration blocs. +# Default : SCTP is prefered. +#Prefer_TCP; + +# Default number of streams per SCTP associations. +# It can be overwritten per peer basis. +# Default : 30 streams +#SCTP_streams = 30; + +############################################################## +## Endpoints configuration + +# Disable use of IP addresses (only IPv6) +# Default : IP enabled +#No_IP; + +# Disable use of IPv6 addresses (only IP) +# Default : IPv6 enabled +#No_IPv6; + +# Specify local addresses where the server must listen +# Default : listen on all addresses available. +#ListenOn = "202.249.37.5"; +#ListenOn = "2001:200:903:2::202:1"; + +############################################################## +## Timers configuration + +# The Tc timer of this peer. +# It is the delay before a new attempt is made to reconnect a disconnected peer. +# The value is expressed in seconds. The recommended value is 30 seconds. +# Default: 30 +#TcTimer = 30; + +# The Tw timer of this peer. +# It is the delay before a watchdog message is sent, as described in RFC 3539. +# The value is expressed in seconds. The default value is 30 seconds. Value must +# be greater or equal to 6 seconds. See details in the RFC. +# Default: 30 +#TwTimer = 30; + +############################################################## +## Applications configuration + +# Disable the relaying of Diameter messages? +# For messages not handled locally, the default behavior is to forward the +# message to another peer if any is available, according to the routing +# algorithms. In addition the "0xffffff" application is advertised in CER/CEA +# exchanges. +# Default: Relaying is enabled. +#NoRelay; + +# Other applications are configured by extensions. + +############################################################## +## Extensions configuration + +# The freeDiameter daemon merely provides support for +# Diameter Base Protocol. The specific application behaviors, +# as well as advanced functions of the daemon, are provided +# by loadable extensions (plug-ins). +# These extensions may in addition receive the name of a +# configuration file, the format of which is extension-specific. + +# Format: +#LoadExtension = "/path/to/extension" [ : "/optional/configuration/file" ] ; +# Exemples: +#LoadExtension = "extensions/sample.so"; +#LoadExtension = "extensions/sample.so":"conf/sample.conf"; + + + +############################################################## +# -------- Test configuration --------- +LocalIdentity = "aaa.koganei.wide.ad.jp"; +LocalRealm = "wide.ad.jp"; +LocalPort = 3866; +LocalSecPort = 3867; +TLS_old_method; +No_IP; +Prefer_TCP; +SCTP_streams = 50; +ListenOn = "202.249.37.5"; +ListenOn = "2001:200:903:2::202:1"; +TcTimer = 60; +TwTimer = 6; +NoRelay; +LoadExtension = "extensions/sample.so"; +LoadExtension = "extensions/sample.so":"conf/sample.conf"; diff -r e5af94b04946 -r 3e143f047f78 extensions/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/CMakeLists.txt Fri Sep 18 18:54:07 2009 +0900 @@ -0,0 +1,75 @@ +PROJECT("freeDiameter extensions" C) + +# We want all resulting objects in the same folder +SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) +# And named fdext_XXX instead of libXXX.so + +#-- faire une macro ici! +SET(FD_EXT_PREFIX "fdext_" PARENT_SCOPE) +SET(FD_EXT_SUFFIX "" PARENT_SCOPE) + +########################### +# Extensions section + +#### +# Diameter applications dictionary +# OPTION(BUILD_DICT_NASREQ "Build NASREQ (RFC4005) Dictionary definitions?" ON) +# IF (BUILD_DICT_NASREQ) +# SUBDIRS(dict_nasreq) +# ENDIF (BUILD_DICT_NASREQ) + +# OPTION(BUILD_DICT_EAP "Build Diameter EAP (RFC4072) Dictionary definitions?" ON) +# IF (BUILD_DICT_EAP) +# SUBDIRS(dict_eap) +# ENDIF (BUILD_DICT_EAP) + + + +#### +# Radius / Diameter gateway extension(s) +# OPTION(BUILD_RADIUS_GW "Build radius_gw? (one-way RADIUS/Diameter gateway - RADIUS NAS <-> Diameter server)" ON) +# IF (BUILD_RADIUS_GW) +# SUBDIRS(radius_gw) +# ENDIF (BUILD_RADIUS_GW) + + +#### +# Routing extensions + +# OPTION(BUILD_RT_DEFAULT "Build rt_default? (Routing extension using Destination-Host, Destination-Realm, and static configuration)" ON) +# IF (BUILD_RT_DEFAULT) +# SUBDIRS(rt_default) +# ENDIF (BUILD_RT_DEFAULT) + + +#### +# Peers security extensions + +# OPTION(BUILD_PS_DEFAULT "Build ps_default? (white-list of peers)" ON) +# IF (BUILD_PS_DEFAULT) +# # -- enable once API is updated: SUBDIRS(ps_default) +# ENDIF (BUILD_PS_DEFAULT) + + +#### +# Debug / development extensions + +OPTION(BUILD_SAMPLE "Build sample? (Simple extension to demonstrate extension mechanism, for developpers only)" OFF) + IF (BUILD_SAMPLE) + SUBDIRS(_sample) + ENDIF (BUILD_SAMPLE) + +# OPTION(BUILD_RT_ANY "Build rt_any? (Routing extension sending message to any peer available, for testing purpose only)" OFF) +# IF (BUILD_RT_ANY) +# SUBDIRS(rt_any) +# ENDIF (BUILD_RT_ANY) + +# OPTION(BUILD_RT_DEBUG "Build rt_debug? (Routing extension tracing routing list, for debug purpose only)" OFF) +# IF (BUILD_RT_DEBUG) +# SUBDIRS(rt_debug) +# ENDIF (BUILD_RT_DEBUG) + +# OPTION(BUILD_APP_TEST "Build app_test? (Testing application to send dummy message to another peer, for testing purpose only)" OFF) +# IF (BUILD_APP_TEST) +# SUBDIRS(app_test) +# ENDIF (BUILD_APP_TEST) diff -r e5af94b04946 -r 3e143f047f78 extensions/_sample/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/_sample/CMakeLists.txt Fri Sep 18 18:54:07 2009 +0900 @@ -0,0 +1,9 @@ +# The sample extension +PROJECT("Sample extension" C) + +# Compile as a module +ADD_LIBRARY(sample MODULE sample.c fini.c) + +# Comply to naming scheme +SET_TARGET_PROPERTIES(sample PROPERTIES PREFIX "${FD_EXT_PREFIX}" ) +SET_TARGET_PROPERTIES(sample PROPERTIES SUFFIX "${FD_EXT_SUFFIX}" ) diff -r e5af94b04946 -r 3e143f047f78 extensions/_sample/fini.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/_sample/fini.c Fri Sep 18 18:54:07 2009 +0900 @@ -0,0 +1,45 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2008, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +/* Sample extension exit point */ + +#include + +void fd_ext_fini(void) +{ + log_debug("Extension is terminated... Bye!\n"); + return ; +} + diff -r e5af94b04946 -r 3e143f047f78 extensions/_sample/sample.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/_sample/sample.c Fri Sep 18 18:54:07 2009 +0900 @@ -0,0 +1,84 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +/* Sample extension to test extensions mechanism in freeDiameter */ +#include + +static int sample_main(char * conffile); + +/* Define the entry point. A convenience macro is provided */ +EXTENSION_ENTRY("sample", sample_main); + +/* The extension-specific initialization code */ +static int sample_main(char * conffile) +{ + TRACE_ENTRY("%p", conffile); + + fprintf(stdout, "I am extension " __FILE__ " running on host %s\n", fd_g_config->diam_id); + + if (conffile) { + fprintf(stdout, "I should parse my configuration file there: %s\n", conffile); + } else { + fprintf(stdout, "I received no configuration file to parse\n"); + } + + /* Use the dictionary for test */ + log_debug("Let's create that 'Example-AVP'...\n"); + { + struct dict_object * origin_host_avp = NULL; + struct dict_object * session_id_avp = NULL; + struct dict_object * example_avp_avp = NULL; + struct dict_rule_data rule_data = { NULL, RULE_REQUIRED, 0, -1, 1 }; + struct dict_avp_data example_avp_data = { 999999, 0, "Example-AVP", AVP_FLAG_VENDOR , 0, AVP_TYPE_GROUPED }; + + CHECK_FCT( fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &origin_host_avp, ENOENT)); + CHECK_FCT( fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &session_id_avp, ENOENT)); + + CHECK_FCT( fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &example_avp_data , NULL, &example_avp_avp )); + + rule_data.rule_avp = origin_host_avp; + rule_data.rule_min = 1; + rule_data.rule_max = 1; + CHECK_FCT( fd_dict_new ( fd_g_config->g_dict, DICT_RULE, &rule_data, example_avp_avp, NULL )); + + rule_data.rule_avp = session_id_avp; + rule_data.rule_min = 1; + rule_data.rule_max = -1; + CHECK_FCT( fd_dict_new ( fd_g_config->g_dict, DICT_RULE, &rule_data, example_avp_avp, NULL )); + } + log_debug("'Example-AVP' created without error\n"); + + return 0; +} diff -r e5af94b04946 -r 3e143f047f78 freeDiameter/CMakeLists.txt --- a/freeDiameter/CMakeLists.txt Fri Sep 04 18:05:25 2009 +0900 +++ b/freeDiameter/CMakeLists.txt Fri Sep 18 18:54:07 2009 +0900 @@ -1,17 +1,28 @@ # The subproject name Project("freeDiameterd" C) -SET(PROJECT_VERSION 0.1) -SET(PROJECT_COPYRIGHT "Copyright (c) 2008-2009, WIDE Project (www.wide.ad.jp) and NICT (www.nict.go.jp)") +# Configuration parser +BISON_FILE(fdd.y) +FLEX_FILE(fdd.l) +SET_SOURCE_FILES_PROPERTIES(lex.fdd.c fdd.tab.c PROPERTIES COMPILE_FLAGS "-I ${CMAKE_CURRENT_SOURCE_DIR}") # List of source files SET(FD_COMMON_SRC fD.h + config.c + extensions.c dict_base_proto.c ) +SET(FD_COMMON_GEN_SRC + lex.fdd.c + fdd.tab.c + fdd.tab.h + ) + + # Building the executable -ADD_EXECUTABLE(freeDiameterd ${FD_COMMON_SRC} main.c) +ADD_EXECUTABLE(freeDiameterd ${FD_COMMON_SRC} ${FD_COMMON_GEN_SRC} main.c) # The link command LINK_DIRECTORIES(${CURRENT_BINARY_DIR}/../libfreeDiameter) @@ -19,6 +30,7 @@ # Save the list of files, if needed SET(FD_COMMON_SRC ${FD_COMMON_SRC} PARENT_SCOPE) +SET(FD_COMMON_GEN_SRC ${FD_COMMON_GEN_SRC} PARENT_SCOPE) # The unary tests directory OPTION(SKIP_TESTS "Skip compilation of the tests?" OFF) diff -r e5af94b04946 -r 3e143f047f78 freeDiameter/config.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/config.c Fri Sep 18 18:54:07 2009 +0900 @@ -0,0 +1,189 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "fD.h" + +/* Configuration management */ + +/* Initialize the fd_g_config structure to default values */ +int fd_conf_init() +{ + TRACE_ENTRY(); + + fd_g_config->eyec = EYEC_CONFIG; + fd_g_config->conf_file = DEFAULT_CONF_FILE; + + fd_g_config->loc_port = 3868; + fd_g_config->loc_port_tls = 3869; + fd_g_config->loc_sctp_str = 30; + fd_list_init(&fd_g_config->loc_endpoints, NULL); + + #ifdef DISABLE_SCTP + fd_g_config->flags.no_sctp = 1; + #endif /* DISABLE_SCTP */ + + fd_g_config->timer_tc = 30; + fd_g_config->timer_tw = 30; + + fd_g_config->or_state_id = (uint32_t) time(NULL); + + CHECK_FCT( fd_dict_init(&fd_g_config->g_dict) ); + CHECK_FCT( fd_fifo_new(&fd_g_config->g_fifo_main) ); + + return 0; +} + +void fd_conf_dump() +{ + if (!TRACE_BOOL(INFO)) + return; + + fd_log_debug("-- Configuration :\n"); + fd_log_debug(" Debug trace level ...... : %+d\n", fd_g_debug_lvl); + fd_log_debug(" Configuration file ..... : %s\n", fd_g_config->conf_file); + fd_log_debug(" Diameter Identity ...... : %s (l:%Zi)\n", fd_g_config->diam_id, fd_g_config->diam_id_len); + fd_log_debug(" Diameter Realm ......... : %s (l:%Zi)\n", fd_g_config->diam_realm, fd_g_config->diam_realm_len); + fd_log_debug(" Local port ............. : %hu\n", fd_g_config->loc_port); + fd_log_debug(" Local secure port ...... : %hu\n", fd_g_config->loc_port_tls); + fd_log_debug(" Number of SCTP streams . : %hu\n", fd_g_config->loc_sctp_str); + if (FD_IS_LIST_EMPTY(&fd_g_config->loc_endpoints)) { + fd_log_debug(" Local endpoints ........ : Default (use all available)\n"); + } else { + struct fd_list * li = fd_g_config->loc_endpoints.next; + fd_log_debug(" Local endpoints ........ : "); + while (li != &fd_g_config->loc_endpoints) { + struct fd_endpoint * ep = (struct fd_endpoint *)li; + if (li != fd_g_config->loc_endpoints.next) fd_log_debug(" "); + sSA_DUMP_NODE( &ep->ss, NI_NUMERICHOST ); + fd_log_debug("\n"); + li = li->next; + } + } + fd_log_debug(" Flags : - IP ........... : %s\n", fd_g_config->flags.no_ip4 ? "DISABLED" : "Enabled"); + fd_log_debug(" - IPv6 ......... : %s\n", fd_g_config->flags.no_ip6 ? "DISABLED" : "Enabled"); + fd_log_debug(" - Relay app .... : %s\n", fd_g_config->flags.no_fwd ? "DISABLED" : "Enabled"); + fd_log_debug(" - TCP .......... : %s\n", fd_g_config->flags.no_tcp ? "DISABLED" : "Enabled"); + #ifdef DISABLE_SCTP + fd_log_debug(" - SCTP ......... : DISABLED (at compilation)\n"); + #else /* DISABLE_SCTP */ + fd_log_debug(" - SCTP ......... : %s\n", fd_g_config->flags.no_sctp ? "DISABLED" : "Enabled"); + #endif /* DISABLE_SCTP */ + fd_log_debug(" - Pref. proto .. : %s\n", fd_g_config->flags.pr_tcp ? "TCP" : "SCTP"); + fd_log_debug(" - TLS method ... : %s\n", fd_g_config->flags.tls_alg ? "INBAND" : "Separate port"); + fd_log_debug(" Tc Timer ............... : %u\n", fd_g_config->timer_tc); + fd_log_debug(" Tw Timer ............... : %u\n", fd_g_config->timer_tw); + fd_log_debug(" Origin-State-Id ........ : %u\n", fd_g_config->or_state_id); +} + +/* Parse the configuration file (using the yacc parser) */ +int fd_conf_parse() +{ + extern FILE * fddin; + + TRACE_DEBUG (FULL, "Parsing configuration file: %s", fd_g_config->conf_file); + + fddin = fopen(fd_g_config->conf_file, "r"); + if (fddin == NULL) { + int ret = errno; + fprintf(stderr, "Unable to open configuration file %s for reading: %s\n", fd_g_config->conf_file, strerror(ret)); + return ret; + } + + /* call yacc parser */ + CHECK_FCT( fddparse(fd_g_config) ); + + /* close the file */ + fclose(fddin); + + /* Resolve hostname if not provided */ + if (fd_g_config->diam_id == NULL) { +#ifndef HOST_NAME_MAX +#define HOST_NAME_MAX 1024 +#endif /* HOST_NAME_MAX */ + char buf[HOST_NAME_MAX + 1]; + struct addrinfo hints, *info; + int ret; + + /* local host name */ + CHECK_SYS(gethostname(buf, sizeof(buf))); + + /* get FQDN */ + memset(&hints, 0, sizeof hints); + hints.ai_flags = AI_CANONNAME; + + ret = getaddrinfo(buf, NULL, &hints, &info); + if (ret != 0) { + fprintf(stderr, "Error resolving local FQDN :\n" + " '%s' : %s\n" + "Please provide LocalIdentity in configuration file.\n", + buf, gai_strerror(ret)); + return EINVAL; + } + CHECK_MALLOC( fd_g_config->diam_id = strdup(info->ai_canonname) ); + freeaddrinfo(info); + } + + /* cache the length of the diameter id for the session module */ + fd_g_config->diam_id_len = strlen(fd_g_config->diam_id); + + /* Handle the realm part */ + if (fd_g_config->diam_realm == NULL) { + char * start = NULL; + + /* Check the diameter identity is a fqdn */ + start = strchr(fd_g_config->diam_id, '.'); + if ((start == NULL) || (start[1] == '\0')) { + fprintf(stderr, "Unable to extract realm from the LocalIdentity '%s'.\n" + "Please fix your LocalIdentity setting or provide LocalRealm.\n", + fd_g_config->diam_id); + return EINVAL; + } + + CHECK_MALLOC( fd_g_config->diam_realm = strdup( start + 1 ) ); + } + fd_g_config->diam_realm_len = strlen(fd_g_config->diam_realm); + + /* Validate some flags */ + if (fd_g_config->flags.no_ip4 && fd_g_config->flags.no_ip6) { + fprintf(stderr, "IP and IPv6 cannot be disabled at the same time.\n"); + return EINVAL; + } + if (fd_g_config->flags.no_tcp && fd_g_config->flags.no_sctp) { + fprintf(stderr, "TCP and SCTP cannot be disabled at the same time.\n"); + return EINVAL; + } + + return 0; +} diff -r e5af94b04946 -r 3e143f047f78 freeDiameter/extensions.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/extensions.c Fri Sep 18 18:54:07 2009 +0900 @@ -0,0 +1,180 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "fD.h" + +#include /* We may use libtool's later for better portability.... */ + +/* plugins management */ + +/* List of extensions to load, from the configuration parsing */ +struct fd_ext_info { + struct fd_list chain; /* link in the list */ + char *filename; /* extension filename. must be a dynamic library with fd_ext_init symbol. */ + char *conffile; /* optional configuration file name for the extension */ + void *handler; /* object returned by dlopen() */ + void (*fini)(void); /* optional address of the fd_ext_fini callback */ +}; + +/* list of extensions */ +static struct fd_list ext_list; + +/* Initialize the module */ +int fd_ext_init() +{ + TRACE_ENTRY(); + fd_list_init(&ext_list, NULL); + return 0; +} + +/* Add new extension */ +int fd_ext_add( char * filename, char * conffile ) +{ + struct fd_ext_info * new; + + TRACE_ENTRY("%p(%s) %p(%s)", filename, filename?filename:"", conffile, conffile?conffile:""); + + /* Check the filename is valid */ + CHECK_PARAMS( filename ); + + /* Create a new object in the list */ + CHECK_MALLOC( new = malloc( sizeof(struct fd_ext_info) ) ); + memset(new, 0, sizeof(struct fd_ext_info)); + fd_list_init(&new->chain, NULL); + new->filename = filename; + new->conffile = conffile; + fd_list_insert_before( &ext_list, &new->chain ); + TRACE_DEBUG (FULL, "Extension %s added to the list.", filename); + return 0; +} + +/* Load all extensions in the list */ +int fd_ext_load() +{ + int ret; + int (*fd_ext_init)(int, int, char *) = NULL; + struct fd_list * li; + + TRACE_ENTRY(); + + /* Loop on all extensions */ + for (li = ext_list.next; li != &ext_list; li = li->next) + { + struct fd_ext_info * ext = (struct fd_ext_info *)li; + TRACE_DEBUG (INFO, "Loading : %s", ext->filename); + + /* Load the extension */ + ext->handler = dlopen(ext->filename, RTLD_LAZY | RTLD_GLOBAL); + if (ext->handler == NULL) { + /* An error occured */ + TRACE_DEBUG( NONE, "Loading of extension %s failed:\n %s\n", ext->filename, dlerror()); + return EINVAL; + } + + /* Resolve the entry point of the extension */ + fd_ext_init = ( int (*) (int, int, char *) )dlsym( ext->handler, "fd_ext_init" ); + + if (fd_ext_init == NULL) { + /* An error occured */ + TRACE_DEBUG( NONE, "Unable to resolve symbol 'fd_ext_init' for extension %s:\n %s\n", ext->filename, dlerror()); + return EINVAL; + } + + /* Resolve the exit point of the extension, which is optional for extensions */ + ext->fini = ( void (*) (void) )dlsym( ext->handler, "fd_ext_fini" ); + + if (ext->fini == NULL) { + /* Not provided */ + TRACE_DEBUG (FULL, "Extension [%s] has no fd_ext_fini function.", ext->filename); + } else { + /* Provided */ + TRACE_DEBUG (FULL, "Extension [%s] fd_ext_fini has been resolved successfully.", ext->filename); + } + + /* Now call the entry point to initialize the extension */ + ret = (*fd_ext_init)( FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR, ext->conffile ); + if (ret != 0) { + /* The extension was unable to load cleanly */ + TRACE_DEBUG( NONE, "Extension %s returned an error during initialization: %s\n", ext->filename, strerror(ret)); + return ret; + } + + /* Proceed to the next extension */ + } + + TRACE_DEBUG (INFO, "All extensions loaded."); + + /* We have finished. */ + return 0; +} + +/* Now unload the extensions and free the memory */ +int fd_ext_fini( void ) +{ + TRACE_ENTRY(); + + /* Loop on all extensions, in FIFO order */ + while (!FD_IS_LIST_EMPTY(&ext_list)) + { + struct fd_list * li = ext_list.next; + struct fd_ext_info * ext = (struct fd_ext_info *)li; + + /* Unlink this element from the list */ + fd_list_unlink(li); + + /* Call the exit point of the extension, if it was resolved */ + if (ext->fini != NULL) { + TRACE_DEBUG (FULL, "Calling [%s]->fd_ext_fini function.", ext->filename); + (*ext->fini)(); + } + + /* Now unload the extension */ + if (ext->handler) { + TRACE_DEBUG (FULL, "Unloading %s", ext->filename); + if ( dlclose(ext->handler) != 0 ) { + TRACE_DEBUG (INFO, "Unloading [%s] failed : %s\n", ext->filename, dlerror()); + } + } + + /* Free the object and continue */ + free(ext->filename); + free(ext->conffile); + free(ext); + } + + /* We always return 0 since we would not handle an error anyway... */ + return 0; +} + diff -r e5af94b04946 -r 3e143f047f78 freeDiameter/fD.h --- a/freeDiameter/fD.h Fri Sep 04 18:05:25 2009 +0900 +++ b/freeDiameter/fD.h Fri Sep 18 18:54:07 2009 +0900 @@ -41,8 +41,24 @@ #include #include +/* Events codespace for fd_g_config->g_fifo_main */ +enum { + FM_TERMINATE = 1000 /* request to terminate */ +}; + +/* Configuration */ +int fd_conf_init(); +void fd_conf_dump(); +int fd_conf_parse(); +int fddparse(struct fd_config * conf); /* yacc generated */ + +/* Extensions */ +int fd_ext_init(); +int fd_ext_add( char * filename, char * conffile ); +int fd_ext_load(); +int fd_ext_fini(void); + /* Create all the dictionary objects defined in the Diameter base RFC. */ int fd_dict_base_protocol(struct dictionary * dict); - #endif /* _FD_H */ diff -r e5af94b04946 -r 3e143f047f78 freeDiameter/fdd.l --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/fdd.l Fri Sep 18 18:54:07 2009 +0900 @@ -0,0 +1,143 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +/* Lex configuration parser. + * + * This file defines the token for parsing the daemon's configuration file + * Note that each extension has a separate independant configuration file. + * + * Note : This module is NOT thread-safe. All processing must be done from one thread only. + */ +%{ +/* Include the daemon's header files */ +#include "fD.h" +/* Include yacc tokens definitions */ +#include "fdd.tab.h" + +/* Update the column information */ +#ifdef DEBUG_LEX +#define YY_USER_ACTION { \ + yylloc->first_column = yylloc->last_column + 1; \ + yylloc->last_column = yylloc->first_column + yyleng - 1; \ + TRACE_DEBUG(FULL, \ + "(%d:%d-%d:%d) matched rule %d, length=%d, txt='%s'\n", \ + yylloc->first_line, yylloc->first_column, \ + yylloc->last_line, yylloc->last_column, \ + yy_act, yyleng, yytext); \ +} +#else /* DEBUG_LEX */ +#define YY_USER_ACTION { \ + yylloc->first_column = yylloc->last_column + 1; \ + yylloc->last_column = yylloc->first_column + yyleng - 1; \ +} +#endif + +/* %option noinput ? */ +#define YY_NO_INPUT +%} + +%option bison-bridge bison-locations +%option noyywrap +%option nounput + +/* Quoted string. Multilines do not match. */ +qstring \"[^\"\n]*\" + +%% + +<*>\n { + /* Update the line count */ + yylloc->first_line++; + yylloc->last_line++; + yylloc->last_column=0; + } + +<*>([[:space:]]{-}[\n])+ ; /* Eat all spaces, not new lines */ +<*>#.*$ ; /* Eat all comments */ + +{qstring} { + /* First copy the string without the quotes for use in the yacc parser */ + CHECK_MALLOC_DO( yylval->string = strdup(yytext+1), /* This allocates one useless tail char but... it's easier :D */ + return LEX_ERROR );/* on error, trig an error in yacc parser */ + + yylval->string[yyleng-2] = '\0'; + + /* the yacc parser will check the string is valid */ + return QSTRING; + } + +[[:digit:]]+ { + /* Convert this to an integer value */ + int ret = sscanf(yytext, "%i", &yylval->integer); + if (ret != 1) { + /* No matching: an error occurred */ + fprintf(stderr, "Unable to convert the value '%s' to a valid number: %s\n", yytext, strerror(errno)); + return LEX_ERROR; /* trig an error in yacc parser */ + /* Maybe we could REJECT instead of failing here? */ + } + return INTEGER; + } + + /* Full words tokens (keywords) */ +(?i:"LocalIdentity") { return LOCALIDENTITY; } +(?i:"LocalRealm") { return LOCALREALM; } +(?i:"LocalPort") { return LOCALPORT; } +(?i:"LocalSecPort") { return LOCALSECPORT; } +(?i:"No_IPv6") { return NOIP6; } +(?i:"No_IP") { return NOIP; } +(?i:"No_TCP") { return NOTCP; } +(?i:"No_SCTP") { return NOSCTP; } +(?i:"Prefer_TCP") { return PREFERTCP; } +(?i:"TLS_old_method") { return OLDTLS; } +(?i:"SCTP_streams") { return SCTPSTREAMS; } +(?i:"ListenOn") { return LISTENON; } +(?i:"TcTimer") { return TCTIMER; } +(?i:"TwTimer") { return TWTIMER; } +(?i:"NoRelay") { return NORELAY; } +(?i:"LoadExtension") { return LOADEXT; } + + + /* Valid single characters for yyparse */ +<*>[=,:;{}] { return yytext[0]; } + + /* Unrecognized token */ +<*>[[:alnum:]]+ | /* This rule is only useful to print a complete token in error messages */ + /* Unrecognized character */ +<*>. { + fprintf(stderr, "Unrecognized text on line %d col %d: '%s'.\n", yylloc->first_line, yylloc->first_column, yytext); + return LEX_ERROR; + } + +%% diff -r e5af94b04946 -r 3e143f047f78 freeDiameter/fdd.y --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/fdd.y Fri Sep 18 18:54:07 2009 +0900 @@ -0,0 +1,261 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +/* Yacc configuration parser. + * + * This file defines the grammar of the configuration file. + * Note that each extension has a separate independant configuration file. + * + * Note : This module is NOT thread-safe. All processing must be done from one thread only. + */ + +/* For development only : */ +%debug +%error-verbose + +%parse-param {struct fd_config * conf} + +/* Keep track of location */ +%locations +%pure-parser + +%{ +#include "fD.h" +#include "fdd.tab.h" /* bug : bison does not define the YYLTYPE before including this bloc, so... */ + +/* The Lex parser prototype */ +int fddlex(YYSTYPE *lvalp, YYLTYPE *llocp); + +/* Function to report error */ +void yyerror (YYLTYPE *ploc, struct fd_config * conf, char const *s) +{ + if (ploc->first_line != ploc->last_line) + fprintf(stderr, "%s:%d.%d-%d.%d : %s\n", conf->conf_file, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s); + else if (ploc->first_column != ploc->last_column) + fprintf(stderr, "%s:%d.%d-%d : %s\n", conf->conf_file, ploc->first_line, ploc->first_column, ploc->last_column, s); + else + fprintf(stderr, "%s:%d.%d : %s\n", conf->conf_file, ploc->first_line, ploc->first_column, s); +} + +%} + +/* Values returned by lex for token */ +%union { + char *string; /* The string is allocated by strdup in lex.*/ + int integer; /* Store integer values */ +} + +/* In case of error in the lexical analysis */ +%token LEX_ERROR + +%token QSTRING +%token INTEGER + +%type extconf + +%token LOCALIDENTITY +%token LOCALREALM +%token LOCALPORT +%token LOCALSECPORT +%token NOIP +%token NOIP6 +%token NOTCP +%token NOSCTP +%token PREFERTCP +%token OLDTLS +%token SCTPSTREAMS +%token LISTENON +%token TCTIMER +%token TWTIMER +%token NORELAY +%token LOADEXT + + +/* -------------------------------------- */ +%% + + /* The grammar definition - Sections blocs. */ +conffile: /* Empty is OK */ + | conffile localidentity + | conffile localrealm + | conffile localport + | conffile localsecport + | conffile noip + | conffile noip6 + | conffile notcp + | conffile nosctp + | conffile prefertcp + | conffile oldtls + | conffile sctpstreams + | conffile listenon + | conffile tctimer + | conffile twtimer + | conffile norelay + | conffile loadext + ; + +localidentity: LOCALIDENTITY '=' QSTRING ';' + { + conf->diam_id = $3; + } + ; + +localrealm: LOCALREALM '=' QSTRING ';' + { + conf->diam_realm = $3; + } + ; + +localport: LOCALPORT '=' INTEGER ';' + { + CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16), + { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); + conf->loc_port = (uint16_t)$3; + } + ; + +localsecport: LOCALSECPORT '=' INTEGER ';' + { + CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16), + { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); + conf->loc_port_tls = (uint16_t)$3; + } + ; + +noip: NOIP ';' + { + conf->flags.no_ip4 = 1; + } + ; + +noip6: NOIP6 ';' + { + conf->flags.no_ip6 = 1; + } + ; + +notcp: NOTCP ';' + { + conf->flags.no_tcp = 1; + } + ; + +nosctp: NOSCTP ';' + { + conf->flags.no_sctp = 1; + } + ; + +prefertcp: PREFERTCP ';' + { + conf->flags.pr_tcp = 1; + } + ; + +oldtls: OLDTLS ';' + { + conf->flags.tls_alg = 1; + } + ; + +sctpstreams: SCTPSTREAMS '=' INTEGER ';' + { + CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16), + { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); + conf->loc_sctp_str = (uint16_t)$3; + } + ; + +listenon: LISTENON '=' QSTRING ';' + { + struct fd_endpoint * ep; + struct addrinfo hints, *ai; + int ret; + + CHECK_MALLOC_DO( ep = malloc(sizeof(struct fd_endpoint)), + { yyerror (&yylloc, conf, "Out of memory"); YYERROR; } ); + memset(ep, 0, sizeof(struct fd_endpoint)); + fd_list_init(&ep->chain, NULL); + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + ret = getaddrinfo($3, NULL, &hints, &ai); + if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; } + + memcpy(&ep->ss, ai->ai_addr, ai->ai_addrlen); + free($3); + freeaddrinfo(ai); + fd_list_insert_before(&conf->loc_endpoints, &ep->chain); + } + ; + +tctimer: TCTIMER '=' INTEGER ';' + { + CHECK_PARAMS_DO( ($3 > 0), + { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); + conf->timer_tc = (unsigned int)$3; + } + ; + +twtimer: TWTIMER '=' INTEGER ';' + { + CHECK_PARAMS_DO( ($3 > 5), + { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); + conf->timer_tw = (unsigned int)$3; + } + ; + +norelay: NORELAY ';' + { + conf->flags.no_fwd = 1; + } + ; + +loadext: LOADEXT '=' QSTRING extconf ';' + { + CHECK_FCT_DO( fd_ext_add( $3, $4 ), + { yyerror (&yylloc, conf, "Error adding extension"); YYERROR; } ); + } + ; + +extconf: /* empty */ + { + $$ = NULL; + } + | ':' QSTRING + { + $$ = $2; + } + ; diff -r e5af94b04946 -r 3e143f047f78 freeDiameter/main.c --- a/freeDiameter/main.c Fri Sep 04 18:05:25 2009 +0900 +++ b/freeDiameter/main.c Fri Sep 18 18:54:07 2009 +0900 @@ -35,22 +35,218 @@ #include "fD.h" +#include +#include + + +/* Display package version */ +static void main_version_core(void) +{ + printf("%s, version %d.%d.%d" +#ifdef HG_VERSION + " (r%s" +# ifdef PACKAGE_HG_REVISION + "/%s" +# endif /* PACKAGE_HG_VERSION */ + ")" +#endif /* HG_VERSION */ + "\n", + FD_PROJECT_NAME, FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR, FD_PROJECT_VERSION_REV +#ifdef HG_VERSION + , HG_VERSION +# ifdef PACKAGE_HG_REVISION + , PACKAGE_HG_REVISION +# endif /* PACKAGE_HG_VERSION */ +#endif /* HG_VERSION */ + ); +} + +/* Display package version and general info */ +static void main_version(void) +{ + main_version_core(); + printf( "%s\n", FD_PROJECT_COPYRIGHT); + printf( "\nSee " FD_PROJECT_NAME " homepage at http://aaa.koganei.wide.ad.jp/\n" + " for information, updates and bug reports on this software.\n"); +} + +/* Print command-line options */ +static void main_help( void ) +{ + main_version_core(); + printf( " This daemon is an implementation of the Diameter protocol\n" + " used for Authentication, Authorization, and Accounting (AAA).\n"); + printf("\nUsage: " FD_PROJECT_BINARY " [OPTIONS]...\n"); + printf( " -h, --help Print help and exit\n" + " -V, --version Print version and exit\n" + " -c, --config=filename Read configuration from this file instead of the \n" + " default location (%s).\n", DEFAULT_CONF_FILE); + printf( "\nDebug:\n" + " These options are mostly useful for developers\n" + " -d, --debug Increase verbosity of debug messages\n" + " -q, --quiet Decrease verbosity then remove debug messages\n"); +} + +/* Parse the command-line */ +static int main_cmdline(int argc, char *argv[]) +{ + int c; + int option_index = 0; + + struct option long_options[] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, + { "config", 1, NULL, 'c' }, + { "debug", 0, NULL, 'd' }, + { "quiet", 0, NULL, 'q' }, + { NULL, 0, NULL, 0 } + }; + + TRACE_ENTRY("%d %p", argc, argv); + + /* Loop on arguments */ + while (1) { + c = getopt_long (argc, argv, "hVc:dq", long_options, &option_index); + if (c == -1) + break; /* Exit from the loop. */ + + switch (c) { + case 'h': /* Print help and exit. */ + main_help(); + exit(0); + + case 'V': /* Print version and exit. */ + main_version(); + exit(0); + + case 'c': /* Read configuration from this file instead of the default location.. */ + CHECK_PARAMS( optarg ); + fd_g_config->conf_file = optarg; + break; + + case 'd': /* Increase verbosity of debug messages. */ + fd_g_debug_lvl++; + break; + + case 'q': /* Decrease verbosity then remove debug messages. */ + fd_g_debug_lvl--; + break; + + case '?': /* Invalid option. */ + /* `getopt_long' already printed an error message. */ + TRACE_DEBUG(INFO, "getopt_long found an invalid character\n"); + return EINVAL; + + default: /* bug: option not considered. */ + TRACE_DEBUG(INFO, "A command-line option is missing in parser: %c\n", c); + ASSERT(0); + return EINVAL; + } + } + + return 0; + +} + +#ifdef HAVE_SIGNALENT_H +const char *const signalstr[] = { +# include "signalent.h" +}; +const int nsignalstr = sizeof signalstr / sizeof signalstr[0]; +# define SIGNALSTR(sig) (((sig) < nsignalstr) ? signalstr[(sig)] : "unknown") +#else /* HAVE_SIGNALENT_H */ +# define SIGNALSTR(sig) ("") +#endif /* HAVE_SIGNALENT_H */ + + +/* signal handler */ +static void * sig_hdl(void * arg) +{ + sigset_t sig_main; + int sig = 0; + + TRACE_ENTRY(); + fd_log_threadname("Main signal handler"); + + sigemptyset(&sig_main); + sigaddset(&sig_main, SIGINT); + sigaddset(&sig_main, SIGTERM); + + CHECK_SYS_DO( sigwait(&sig_main, &sig), TRACE_DEBUG(INFO, "Error in sigwait function") ); + + TRACE_DEBUG(INFO, "Received signal %s (%d), exiting", SIGNALSTR(sig), sig); + CHECK_FCT_DO( fd_event_send(fd_g_config->g_fifo_main, FM_TERMINATE, NULL), exit(2) ); + return NULL; +} + +/* The static configuration structure */ +static struct fd_config conf; +struct fd_config * fd_g_config = &conf; + /* Entry point */ int main(int argc, char * argv[]) { + int ret; + pthread_t sig_th; + sigset_t sig_all; + + memset(fd_g_config, 0, sizeof(struct fd_config)); + sigfillset(&sig_all); + CHECK_POSIX( pthread_sigmask(SIG_BLOCK, &sig_all, NULL) ); + /* Initialize the library */ CHECK_FCT( fd_lib_init() ); /* Name this thread */ fd_log_threadname("Main"); + + /* Initialize the config */ + CHECK_FCT( fd_conf_init() ); - /* Initialize the dictionary */ - CHECK_FCT( fd_dict_init(&fd_g_dict) ); + /* Parse the command-line */ + CHECK_FCT( main_cmdline(argc, argv) ); + + /* Allow SIGINT and SIGTERM from this point */ + CHECK_POSIX( pthread_create(&sig_th, NULL, sig_hdl, NULL) ); /* Add definitions of the base protocol */ - CHECK_FCT( fd_dict_base_protocol(fd_g_dict) ); + CHECK_FCT( fd_dict_base_protocol(fd_g_config->g_dict) ); + + /* Initialize other modules */ + CHECK_FCT( fd_ext_init() ); + + /* Parse the configuration file */ + CHECK_FCT( fd_conf_parse() ); + + /* Load the dynamic extensions */ + CHECK_FCT( fd_ext_load() ); + + /* Start the peer state machines */ + - TRACE_DEBUG(INFO, "freeDiameter daemon initialized."); + /* Now, just wait for events */ + TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized."); + fd_conf_dump(); + while (1) { + int code; + CHECK_FCT_DO( fd_event_get(fd_g_config->g_fifo_main, &code, NULL), break ); + switch (code) { + case FM_TERMINATE: + ret = 0; + goto end; + + default: + TRACE_DEBUG(INFO, "Unexpected event in the daemon (%d), terminating.\n", code); + ret = -1; + goto end; + } + } - return 0; +end: + TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon is stopping..."); + + /* cleanups */ + CHECK_FCT( fd_thr_term(&sig_th) ); + + return ret; } diff -r e5af94b04946 -r 3e143f047f78 freeDiameter/tests/CMakeLists.txt --- a/freeDiameter/tests/CMakeLists.txt Fri Sep 04 18:05:25 2009 +0900 +++ b/freeDiameter/tests/CMakeLists.txt Fri Sep 18 18:54:07 2009 +0900 @@ -14,7 +14,7 @@ testlist testdict testmesg - testmq + testqueues testsess testdisp ) @@ -28,15 +28,18 @@ INCLUDE_DIRECTORIES( ".." ) INCLUDE_DIRECTORIES( "../../libfreeDiameter" ) +BISON_FILE(../fdd.y) +FLEX_FILE(../fdd.l) + SET(TEST_COMMON_SRC "") FOREACH( SRC_FILE ${FD_COMMON_SRC}) SET(TEST_COMMON_SRC ${TEST_COMMON_SRC} "../${SRC_FILE}") ENDFOREACH(SRC_FILE) -# FOREACH( SRC_FILE ${FD_COMMON_GEN_SRC}) -# SET(TEST_COMMON_SRC ${TEST_COMMON_SRC} "${CMAKE_CURRENT_BINARY_DIR}/../${SRC_FILE}") -# ENDFOREACH(SRC_FILE) +FOREACH( SRC_FILE ${FD_COMMON_GEN_SRC}) + SET(TEST_COMMON_SRC ${TEST_COMMON_SRC} "${CMAKE_CURRENT_BINARY_DIR}/../${SRC_FILE}") +ENDFOREACH(SRC_FILE) FOREACH( SRC_FILE ${LFD_SRC}) SET(TEST_COMMON_SRC ${TEST_COMMON_SRC} "../../libfreeDiameter/${SRC_FILE}") diff -r e5af94b04946 -r 3e143f047f78 freeDiameter/tests/testdict.c --- a/freeDiameter/tests/testdict.c Fri Sep 04 18:05:25 2009 +0900 +++ b/freeDiameter/tests/testdict.c Fri Sep 18 18:54:07 2009 +0900 @@ -66,24 +66,24 @@ /* Create two vendors */ - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_VENDOR, &vendor1_data , NULL, &obj1 ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_VENDOR, &vendor2_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_VENDOR, &vendor1_data , NULL, &obj1 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_VENDOR, &vendor2_data , NULL, NULL ) ); /* Check we always retrieve the correct vendor object */ - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, &obj2, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, &obj2, ENOENT ) ); CHECK( obj1, obj2); - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 1", &obj2, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 1", &obj2, ENOENT ) ); CHECK( obj1, obj2); /* Check the error conditions */ - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, NULL, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, NULL, ENOENT ) ); vendor_id = 735673; /* Not defined */ - CHECK( ENOENT, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, NULL, ENOENT ) ); - CHECK( ENOENT, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", NULL, ENOENT ) ); - CHECK( ENOENT, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, &obj2, ENOENT ) ); - CHECK( ENOENT, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", &obj2, ENOENT ) ); - CHECK( ENOTSUP, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", &obj2, ENOTSUP ) ); + CHECK( ENOENT, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, NULL, ENOENT ) ); + CHECK( ENOENT, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", NULL, ENOENT ) ); + CHECK( ENOENT, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, &obj2, ENOENT ) ); + CHECK( ENOENT, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", &obj2, ENOENT ) ); + CHECK( ENOTSUP, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", &obj2, ENOTSUP ) ); /* Check the get_* functions */ CHECK( 0, fd_dict_getval ( obj1, &vendor1_data ) ); @@ -93,10 +93,10 @@ CHECK( EINVAL, fd_dict_getval ( (struct dict_object *)"not an object", &vendor1_data ) ); /* Create the application with vendor1 as parent */ - CHECK( EINVAL, fd_dict_new ( fd_g_dict, DICT_APPLICATION, &app1_data , (struct dict_object *)"bad object", &obj2 ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_APPLICATION, &app1_data , obj1, &obj2 ) ); + CHECK( EINVAL, fd_dict_new ( fd_g_config->g_dict, DICT_APPLICATION, &app1_data , (struct dict_object *)"bad object", &obj2 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_APPLICATION, &app1_data , obj1, &obj2 ) ); - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_VENDOR, VENDOR_OF_APPLICATION, obj2, &obj3, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_OF_APPLICATION, obj2, &obj3, ENOENT ) ); CHECK( obj1, obj3); /* Creating and searching the other objects is already done in dictionary initialization */ @@ -111,20 +111,20 @@ struct dict_rule_data rule_data = { NULL, RULE_REQUIRED, -1, -1 }; struct dict_avp_data example_avp_data = { 999999, 0, "Example-AVP", AVP_FLAG_VENDOR , 0, AVP_TYPE_GROUPED }; - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &origin_host_avp, ENOENT ) ); - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &session_id_avp, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &origin_host_avp, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &session_id_avp, ENOENT ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &example_avp_data , NULL, &example_avp_avp ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &example_avp_data , NULL, &example_avp_avp ) ); rule_data.rule_avp = origin_host_avp; rule_data.rule_min = 1; rule_data.rule_max = 1; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_RULE, &rule_data, example_avp_avp, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_RULE, &rule_data, example_avp_avp, NULL ) ); rule_data.rule_avp = session_id_avp; rule_data.rule_min = 1; rule_data.rule_max = -1; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_RULE, &rule_data, example_avp_avp, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_RULE, &rule_data, example_avp_avp, NULL ) ); CHECK( 0, fd_dict_iterate_rules ( example_avp_avp, &nbr, iter_test) ); CHECK( 2, nbr ); diff -r e5af94b04946 -r 3e143f047f78 freeDiameter/tests/testdisp.c --- a/freeDiameter/tests/testdisp.c Fri Sep 04 18:05:25 2009 +0900 +++ b/freeDiameter/tests/testdisp.c Fri Sep 18 18:54:07 2009 +0900 @@ -127,15 +127,15 @@ struct dict_enumval_data enu1_data = { "ENU test 1", { .u32 = 1 }}; struct dict_enumval_data enu2_data = { "ENU test 2", { .u32 = 2 }}; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_APPLICATION, &app1_data, NULL, &app1 ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_APPLICATION, &app2_data, NULL, &app2 ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_COMMAND, &cmd1_data, NULL, &cmd1 ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_COMMAND, &cmd2_data, NULL, &cmd2 ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_TYPE, &type_data, NULL, &enutype ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp1_data, NULL, &avp1 ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp2_data, enutype, &avp2 ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_ENUMVAL, &enu1_data, enutype, &enu1 ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_ENUMVAL, &enu2_data, enutype, &enu2 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_APPLICATION, &app1_data, NULL, &app1 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_APPLICATION, &app2_data, NULL, &app2 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_COMMAND, &cmd1_data, NULL, &cmd1 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_COMMAND, &cmd2_data, NULL, &cmd2 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_TYPE, &type_data, NULL, &enutype ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp1_data, NULL, &avp1 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp2_data, enutype, &avp2 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &enu1_data, enutype, &enu1 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &enu2_data, enutype, &enu2 ) ); } /* Register first handler, very simple test */ diff -r e5af94b04946 -r 3e143f047f78 freeDiameter/tests/testmesg.c --- a/freeDiameter/tests/testmesg.c Fri Sep 04 18:05:25 2009 +0900 +++ b/freeDiameter/tests/testmesg.c Fri Sep 18 18:54:07 2009 +0900 @@ -50,7 +50,7 @@ struct dict_object * acr_model = NULL; /* Now find the ACR dictionary object */ - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) ); /* Create the instance, using the templates */ CHECK( 0, fd_msg_new ( acr_model, 0, &acr ) ); @@ -70,7 +70,7 @@ struct dict_object * pi_model = NULL; /* Now find the ACR dictionary object */ - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_AVP, AVP_BY_NAME, "Proxy-Info", &pi_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "Proxy-Info", &pi_model, ENOENT ) ); /* Create the instance, using the templates */ CHECK( 0, fd_msg_avp_new ( pi_model, 0, &pi ) ); @@ -132,7 +132,7 @@ struct dict_object * rr_model = NULL; /* Now find the dictionary object */ - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_AVP, AVP_BY_NAME, "Route-Record", &rr_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "Route-Record", &rr_model, ENOENT ) ); /* Create the instance, using the templates */ CHECK( 0, fd_msg_avp_new ( rr_model, 0, &avp1 ) ); @@ -160,7 +160,7 @@ struct dict_object * acr_model = NULL; /* Now find the ACR dictionary object */ - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) ); /* Create the instance, using the templates */ CHECK( 0, fd_msg_new ( acr_model, 0, &acr ) ); @@ -172,25 +172,25 @@ struct dict_object * vendor; { struct dict_vendor_data vendor_data = { 73565, "Vendor test" }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_VENDOR, &vendor_data , NULL, &vendor ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_VENDOR, &vendor_data , NULL, &vendor ) ); } { struct dict_application_data app_data = { 73566, "Application test" }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_APPLICATION, &app_data , vendor, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_APPLICATION, &app_data , vendor, NULL ) ); } { struct dict_avp_data avp_data = { 73567, 0, "AVP Test - no vendor - f32", 0, 0, AVP_TYPE_FLOAT32 }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { struct dict_object * type = NULL; struct dict_type_data type_data = { AVP_TYPE_INTEGER64, "Int64 test" }; struct dict_avp_data avp_data = { 73568, 73565, "AVP Test - i64", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_INTEGER64 }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_TYPE, &type_data , NULL, &type ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_TYPE, &type_data , NULL, &type ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , type, NULL ) ); } { @@ -201,19 +201,19 @@ struct dict_enumval_data val3 = { "i32 const test (val -5)",{ .i32 = -5 } }; struct dict_avp_data avp_data = { 73569, 73565, "AVP Test - enumi32", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_INTEGER32 }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_TYPE, &type_data , NULL, &type ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , type, NULL ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_ENUMVAL, &val1 , type, NULL ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_ENUMVAL, &val2 , type, NULL ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_ENUMVAL, &val3 , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_TYPE, &type_data , NULL, &type ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &val1 , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &val2 , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &val3 , type, NULL ) ); } { struct dict_object * type = NULL; struct dict_type_data type_data = { AVP_TYPE_OCTETSTRING, "OS test" }; struct dict_avp_data avp_data = { 73570, 73565, "AVP Test - os", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_OCTETSTRING }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_TYPE, &type_data , NULL, &type ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_TYPE, &type_data , NULL, &type ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , type, NULL ) ); } { @@ -224,31 +224,31 @@ struct dict_enumval_data val3 = { "os const test (waa)", { .os = { (unsigned char *)"waaad", 3 } } }; struct dict_avp_data avp_data = { 73571, 73565, "AVP Test - enumos", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_OCTETSTRING }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_TYPE, &type_data , NULL, &type ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , type, NULL ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_ENUMVAL, &val1 , type, NULL ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_ENUMVAL, &val2 , type, NULL ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_ENUMVAL, &val3 , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_TYPE, &type_data , NULL, &type ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &val1 , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &val2 , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &val3 , type, NULL ) ); } { struct dict_object * gavp = NULL; struct dict_avp_data avp_data = { 73572, 73565, "AVP Test - grouped", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_GROUPED }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, &gavp ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, &gavp ) ); /* Macro to search AVP and create a rule */ #define ADD_RULE( _parent, _vendor, _avpname, _pos, _min, _max, _ord ) { \ struct dict_object * _avp = NULL; \ struct dict_avp_request _req = { (_vendor), 0, (_avpname) }; \ struct dict_rule_data _data; \ - CHECK( 0, fd_dict_search( fd_g_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\ + CHECK( 0, fd_dict_search( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\ _data.rule_avp = _avp; \ _data.rule_position = (_pos); \ _data.rule_order = (_ord); \ _data.rule_min = (_min); \ _data.rule_max = (_max); \ - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_RULE, &_data , (_parent), NULL ) ); \ + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_RULE, &_data , (_parent), NULL ) ); \ } ADD_RULE(gavp, 73565, "AVP Test - os", RULE_OPTIONAL, -1, -1, 0); @@ -260,8 +260,8 @@ struct dict_object * command = NULL; struct dict_cmd_data cmd_data = { 73573, "Test-Command-Request", CMD_FLAG_REQUEST, CMD_FLAG_REQUEST }; - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Application test", &application, ENOENT ) ); - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_COMMAND, &cmd_data , application, &command ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Application test", &application, ENOENT ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_COMMAND, &cmd_data , application, &command ) ); ADD_RULE(command, 0, "AVP Test - no vendor - f32", RULE_FIXED_HEAD, -1, 1, 1); ADD_RULE(command, 73565, "AVP Test - i64", RULE_REQUIRED, -1, -1, 0); ADD_RULE(command, 73565, "AVP Test - enumi32", RULE_OPTIONAL, -1, -1, 0); @@ -274,7 +274,7 @@ struct dict_object * gavp = NULL; struct dict_avp_data avp_data = { 73574, 73565, "AVP Test - rules", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_GROUPED }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, &gavp ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, &gavp ) ); ADD_RULE(gavp, 0, "AVP Test - no vendor - f32", RULE_FIXED_HEAD, 0, 1, 1); ADD_RULE(gavp, 73565, "AVP Test - i64", RULE_FIXED_HEAD, -1, 1, 2); @@ -302,11 +302,11 @@ struct avp * avp = NULL; union avp_value value; - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) ); /* Check an error is trigged if the AVP has no value set */ { - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_AVP, AVP_BY_NAME, "AVP Test - no vendor - f32", &avp_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "AVP Test - no vendor - f32", &avp_model, ENOENT ) ); CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) ); CHECK( 0, fd_msg_avp_new ( avp_model, 0, &avp ) ); @@ -328,7 +328,7 @@ #define ADD_AVP( _parent, _position, _avpi, _avpvendor, _avpname) { \ struct dict_object * _avp = NULL; \ struct dict_avp_request _req = { (_avpvendor), 0, (_avpname) }; \ - CHECK( 0, fd_dict_search( fd_g_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\ + CHECK( 0, fd_dict_search( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\ CHECK( 0, fd_msg_avp_new ( _avp, 0, &_avpi ) ); \ CHECK( 0, fd_msg_avp_add ( (_parent), (_position), _avpi ) ); \ } @@ -377,11 +377,11 @@ struct dict_enumval_request request; CHECK( 0, fd_msg_model ( avpi, &avp_model ) ); - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); memset(&request, 0, sizeof(request)); request.type_obj = type_model; request.search.enum_name = "i32 const test (val 2)"; - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); CHECK( 0, fd_dict_getval ( value_model, &request.search ) ); CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) ); #if 0 @@ -398,11 +398,11 @@ struct dict_enumval_request request; CHECK( 0, fd_msg_model ( avpi, &avp_model ) ); - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); memset(&request, 0, sizeof(request)); request.type_obj = type_model; request.search.enum_name = "i32 const test (val -5)"; - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); CHECK( 0, fd_dict_getval ( value_model, &request.search ) ); CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) ); #if 0 @@ -457,11 +457,11 @@ struct dict_enumval_request request; CHECK( 0, fd_msg_model ( avpi, &avp_model ) ); - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); memset(&request, 0, sizeof(request)); request.type_obj = type_model; request.search.enum_name = "os const test (waaad)"; - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); CHECK( 0, fd_dict_getval ( value_model, &request.search ) ); CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) ); #if 0 @@ -482,11 +482,11 @@ struct dict_enumval_request request; CHECK( 0, fd_msg_model ( avpi, &avp_model ) ); - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); memset(&request, 0, sizeof(request)); request.type_obj = type_model; request.search.enum_name = "os const test (waa)"; - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); CHECK( 0, fd_dict_getval ( value_model, &request.search ) ); CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) ); #if 0 @@ -653,7 +653,7 @@ struct avp_hdr * avpdata = NULL; /* Now find the ACR dictionary object */ - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_AVP, AVP_BY_NAME, "AVP Test - no vendor - f32", &avp_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "AVP Test - no vendor - f32", &avp_model, ENOENT ) ); CPYBUF(); CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) ); @@ -679,7 +679,7 @@ /* Change the command-code */ buf_cpy[5] = 0x11; CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) ); - CHECK( ENOTSUP, fd_msg_parse_dict( msg, fd_g_dict ) ); + CHECK( ENOTSUP, fd_msg_parse_dict( msg, fd_g_config->g_dict ) ); /* reset */ CHECK( 0, fd_msg_free ( msg ) ); @@ -694,7 +694,7 @@ /* Check that we cannot support this message now */ CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) ); - CHECK( ENOTSUP, fd_msg_parse_dict( msg, fd_g_dict ) ); + CHECK( ENOTSUP, fd_msg_parse_dict( msg, fd_g_config->g_dict ) ); /* reset */ CHECK( 0, fd_msg_free ( msg ) ); @@ -708,7 +708,7 @@ /* Check that we can support this message now */ CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) ); - CHECK( 0, fd_msg_parse_dict( msg, fd_g_dict ) ); + CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->g_dict ) ); #if 0 fd_msg_dump_walk(0, msg); @@ -719,7 +719,7 @@ } CHECK( 0, fd_msg_parse_buffer( &buf, 344, &msg) ); - CHECK( 0, fd_msg_parse_dict( msg, fd_g_dict ) ); + CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->g_dict ) ); #if 0 fd_msg_dump_walk(0, msg); #endif @@ -729,7 +729,7 @@ { struct dict_object * rule; - CHECK( 0, fd_msg_parse_rules( msg, fd_g_dict, &rule ) ); + CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->g_dict, &rule ) ); /* Use the "AVP Test - rules" AVP to test the rules */ { @@ -748,26 +748,26 @@ ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - grouped" ); /* Check the message is still conform */ - CHECK( 0, fd_msg_parse_rules( msg, fd_g_dict, &rule ) ); + CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->g_dict, &rule ) ); /* The first avp is optional in fixed position, so remove it and check the message is still OK */ CHECK( 0, fd_msg_browse ( tavp, MSG_BRW_FIRST_CHILD, &childavp, NULL) ); CHECK( 0, fd_msg_free ( childavp ) ); - CHECK( 0, fd_msg_parse_rules( msg, fd_g_dict, &rule ) ); + CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->g_dict, &rule ) ); ADD_AVP( tavp, MSG_BRW_FIRST_CHILD, childavp, 0, "AVP Test - no vendor - f32" ); /* Now break some rules and check it is detected */ #define CHECK_CONFLICT( _msg, _ruleavp, _avpvendor ) { \ struct dict_object * _rule; \ - CHECK( EBADMSG, fd_msg_parse_rules( _msg, fd_g_dict, &_rule ) ); \ + CHECK( EBADMSG, fd_msg_parse_rules( _msg, fd_g_config->g_dict, &_rule ) ); \ if ((_ruleavp) == NULL) { \ CHECK( NULL, _rule); \ } else { \ struct dict_rule_data _ruledata; \ struct dict_object * _avp; \ struct dict_avp_request _req = { (_avpvendor), 0, (_ruleavp) }; \ - CHECK( 0, fd_dict_search( fd_g_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT)); \ + CHECK( 0, fd_dict_search( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT)); \ CHECK( 0, fd_dict_getval( _rule, &_ruledata ) ); \ CHECK( _avp, _ruledata.rule_avp ); \ } \ @@ -823,7 +823,7 @@ ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - enumos" ); /* The message is still conform */ - CHECK( 0, fd_msg_parse_rules( msg, fd_g_dict, &rule ) ); + CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->g_dict, &rule ) ); /* Now break the rule */ ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - enumos" ); @@ -864,10 +864,10 @@ struct sockaddr_in6 sin6, *psin6; /* Find the CER dictionary object */ - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer_model, ENOENT ) ); /* Now find the Host-IP-Address dictionary object */ - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_AVP, AVP_BY_NAME, "Host-IP-Address", &hia_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "Host-IP-Address", &hia_model, ENOENT ) ); /* Create the msg instance */ CHECK( 0, fd_msg_new ( cer_model, 0, &cer ) ); @@ -944,7 +944,7 @@ /* Ok, now let's recreate the message */ CHECK( 0, fd_msg_parse_buffer( &buf, 64, &cer) ); - CHECK( 0, fd_msg_parse_dict( cer, fd_g_dict ) ); + CHECK( 0, fd_msg_parse_dict( cer, fd_g_config->g_dict ) ); /* Get the pointers to the first and last AVP */ CHECK( 0, fd_msg_browse( cer, MSG_BRW_FIRST_CHILD, &avp4, NULL) ); @@ -971,31 +971,31 @@ { { struct dict_avp_data avp_data = { 91001, 0, "AVP Test 2 - os", 0, 0, AVP_TYPE_OCTETSTRING }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { struct dict_avp_data avp_data = { 91002, 0, "AVP Test 2 - i32", 0, 0, AVP_TYPE_INTEGER32 }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { struct dict_avp_data avp_data = { 91003, 0, "AVP Test 2 - i64", 0, 0, AVP_TYPE_INTEGER64 }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { struct dict_avp_data avp_data = { 91004, 0, "AVP Test 2 - u32", 0, 0, AVP_TYPE_UNSIGNED32 }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { struct dict_avp_data avp_data = { 91005, 0, "AVP Test 2 - u64", 0, 0, AVP_TYPE_UNSIGNED64 }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { struct dict_avp_data avp_data = { 91006, 0, "AVP Test 2 - f32", 0, 0, AVP_TYPE_FLOAT32 }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { struct dict_avp_data avp_data = { 91007, 0, "AVP Test 2 - f64", 0, 0, AVP_TYPE_FLOAT64 }; - CHECK( 0, fd_dict_new ( fd_g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { @@ -1009,7 +1009,7 @@ struct avp_hdr * avpdata = NULL; struct msg_hdr * msgdata = NULL; - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) ); /* Create a message */ CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) ); @@ -1174,7 +1174,7 @@ CHECK( 0, fd_msg_free( msg ) ); CHECK( 0, fd_msg_parse_buffer( &buf, 148, &msg) ); - CHECK( 0, fd_msg_parse_dict( msg, fd_g_dict ) ); + CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->g_dict ) ); #if 0 fd_msg_dump_walk(0, msg); #endif diff -r e5af94b04946 -r 3e143f047f78 freeDiameter/tests/testmq.c --- a/freeDiameter/tests/testmq.c Fri Sep 04 18:05:25 2009 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,423 +0,0 @@ -/********************************************************************************************************* -* Software License Agreement (BSD License) * -* Author: Sebastien Decugis * -* * -* Copyright (c) 2009, WIDE Project and NICT * -* All rights reserved. * -* * -* Redistribution and use of this software in source and binary forms, with or without modification, are * -* permitted provided that the following conditions are met: * -* * -* * Redistributions of source code must retain the above * -* copyright notice, this list of conditions and the * -* following disclaimer. * -* * -* * Redistributions in binary form must reproduce the above * -* copyright notice, this list of conditions and the * -* following disclaimer in the documentation and/or other * -* materials provided with the distribution. * -* * -* * Neither the name of the WIDE Project or NICT nor the * -* names of its contributors may be used to endorse or * -* promote products derived from this software without * -* specific prior written permission of WIDE Project and * -* NICT. * -* * -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * -* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * -* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * -* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -*********************************************************************************************************/ - -#include "tests.h" - -/* Structure for testing threshold function */ -static struct thrh_test { - struct mqueue * queue; /* pointer to the queue */ - int h_calls; /* number of calls of h_cb */ - int l_calls; /* number of calls of l_cb */ -} thrh_td; - -/* Callbacks for threasholds test */ -void thrh_cb_h(struct mqueue *queue, void **data) -{ - if (thrh_td.h_calls == thrh_td.l_calls) { - CHECK( NULL, *data ); - *data = &thrh_td; - } else { - CHECK( *data, &thrh_td ); - } - CHECK( queue, thrh_td.queue ); - - /* Update the count */ - thrh_td.h_calls ++; -} -void thrh_cb_l(struct mqueue *queue, void **data) -{ - CHECK( 1, data ? 1 : 0 ); - CHECK( *data, &thrh_td ); - - /* Check the queue parameter is correct */ - CHECK( queue, thrh_td.queue ); - - /* Update the count */ - thrh_td.l_calls ++; - /* Cleanup the data ptr if needed */ - if (thrh_td.l_calls == thrh_td.h_calls) - *data = NULL; - /* done */ -} - - -/* Structure that is passed to the test function */ -struct test_data { - struct mqueue * queue; /* pointer to the queue */ - pthread_barrier_t * bar; /* if not NULL, barrier to synchronize before getting messages */ - struct timespec * ts; /* if not NULL, use a timedget instead of a get */ - int nbr; /* number of messages to retrieve from the queue */ -}; - -/* The test function, to be threaded */ -static void * test_fct(void * data) -{ - int ret = 0, i; - struct msg * msg = NULL; - struct test_data * td = (struct test_data *) data; - - if (td->bar != NULL) { - ret = pthread_barrier_wait(td->bar); - if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { - CHECK( 0, ret); - } else { - CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret); /* just for the traces */ - } - } - - for (i=0; i< td->nbr; i++) { - if (td->ts != NULL) { - CHECK( 0, fd_mq_timedget(td->queue, &msg, td->ts) ); - } else { - CHECK( 0, fd_mq_get(td->queue, &msg) ); - } - } - - return NULL; -} - - -/* Main test routine */ -int main(int argc, char *argv[]) -{ - struct timespec ts; - - struct msg * msg1 = NULL; - struct msg * msg2 = NULL; - struct msg * msg3 = NULL; - - /* First, initialize the daemon modules */ - INIT_FD(); - - /* Prolog: create the messages */ - { - struct dict_object * acr_model = NULL; - struct dict_object * cer_model = NULL; - struct dict_object * dwr_model = NULL; - - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) ); - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer_model, ENOENT ) ); - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &dwr_model, ENOENT ) ); - CHECK( 0, fd_msg_new ( acr_model, 0, &msg1 ) ); - CHECK( 0, fd_msg_new ( cer_model, 0, &msg2 ) ); - CHECK( 0, fd_msg_new ( dwr_model, 0, &msg3 ) ); - } - - /* Basic operation */ - { - struct mqueue * queue = NULL; - int count; - struct msg * msg = NULL; - - /* Create the queue */ - CHECK( 0, fd_mq_new(&queue) ); - - /* Check the count is 0 */ - CHECK( 0, fd_mq_length(queue, &count) ); - CHECK( 0, count); - - /* Now enqueue */ - msg = msg1; - CHECK( 0, fd_mq_post(queue, &msg) ); - msg = msg2; - CHECK( 0, fd_mq_post(queue, &msg) ); - msg = msg3; - CHECK( 0, fd_mq_post(queue, &msg) ); - - /* Check the count is 3 */ - CHECK( 0, fd_mq_length(queue, &count) ); - CHECK( 3, count); - - /* Retrieve the first message using fd_mq_get */ - CHECK( 0, fd_mq_get(queue, &msg) ); - CHECK( msg1, msg); - CHECK( 0, fd_mq_length(queue, &count) ); - CHECK( 2, count); - - /* Retrieve the second message using fd_mq_timedget */ - CHECK(0, clock_gettime(CLOCK_REALTIME, &ts)); - ts.tv_sec += 1; /* Set the timeout to 1 second */ - CHECK( 0, fd_mq_timedget(queue, &msg, &ts) ); - CHECK( msg2, msg); - CHECK( 0, fd_mq_length(queue, &count) ); - CHECK( 1, count); - - /* Retrieve the third message using meq_tryget */ - CHECK( 0, fd_mq_tryget(queue, &msg) ); - CHECK( msg3, msg); - CHECK( 0, fd_mq_length(queue, &count) ); - CHECK( 0, count); - - /* Check that another meq_tryget does not block */ - CHECK( EWOULDBLOCK, fd_mq_tryget(queue, &msg) ); - CHECK( 0, fd_mq_length(queue, &count) ); - CHECK( 0, count); - - /* We're done for basic tests */ - CHECK( 0, fd_mq_del(&queue) ); - } - - /* Test robustness, ensure no messages are lost */ - { -#define NBR_MSG 200 -#define NBR_THREADS 60 - struct mqueue *queue = NULL; - pthread_barrier_t bar; - struct test_data td_1; - struct test_data td_2; - struct msg *msgs[NBR_MSG * NBR_THREADS * 2], *msg; - pthread_t thr [NBR_THREADS * 2]; - struct dict_object *dwr_model = NULL; - int count; - int i; - - /* Create the queue */ - CHECK( 0, fd_mq_new(&queue) ); - - /* Create the barrier */ - CHECK( 0, pthread_barrier_init(&bar, NULL, NBR_THREADS * 2 + 1) ); - - /* Initialize the ts */ - CHECK(0, clock_gettime(CLOCK_REALTIME, &ts)); - ts.tv_sec += 2; /* Set the timeout to 2 second */ - - /* Create the messages */ - CHECK( 0, fd_dict_search ( fd_g_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &dwr_model, ENOENT ) ); - for (i = 0; i < NBR_MSG * NBR_THREADS * 2; i++) { - CHECK( 0, fd_msg_new ( dwr_model, 0, &msgs[i] ) ); - } - - /* Initialize the test data structures */ - td_1.queue = queue; - td_1.bar = &bar; - td_1.ts = &ts; - td_1.nbr = NBR_MSG; - td_2.queue = queue; - td_2.bar = &bar; - td_2.ts = NULL; - td_2.nbr = NBR_MSG; - - /* Create the threads */ - for (i=0; i < NBR_THREADS * 2; i++) { - CHECK( 0, pthread_create( &thr[i], NULL, test_fct, (i & 1) ? &td_1 : &td_2 ) ); - } - - /* Synchronize everyone */ - { - int ret = pthread_barrier_wait(&bar); - if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { - CHECK( 0, ret); - } else { - CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret); /* for trace only */ - } - } - - /* Now post all the messages */ - for (i=0; i < NBR_MSG * NBR_THREADS * 2; i++) { - msg = msgs[i]; - CHECK( 0, fd_mq_post(queue, &msg) ); - } - - /* Join all threads. This blocks if messages are lost... */ - for (i=0; i < NBR_THREADS * 2; i++) { - CHECK( 0, pthread_join( thr[i], NULL ) ); - } - - /* Check the count of the queue is back to 0 */ - CHECK( 0, fd_mq_length(queue, &count) ); - CHECK( 0, count); - - /* Destroy this queue and the messages */ - CHECK( 0, fd_mq_del(&queue) ); - for (i=0; i < NBR_MSG * NBR_THREADS * 2; i++) { - CHECK( 0, fd_msg_free( msgs[i] ) ); - } - } - - /* Test thread cancelation */ - { - struct mqueue *queue = NULL; - pthread_barrier_t bar; - struct test_data td; - pthread_t th; - - /* Create the queue */ - CHECK( 0, fd_mq_new(&queue) ); - - /* Create the barrier */ - CHECK( 0, pthread_barrier_init(&bar, NULL, 2) ); - - /* Initialize the ts */ - CHECK(0, clock_gettime(CLOCK_REALTIME, &ts)); - ts.tv_sec += 2; /* Set the timeout to 2 second */ - - /* Initialize the test data structures */ - td.queue = queue; - td.bar = &bar; - td.ts = &ts; - td.nbr = 1; - - /* Create the thread */ - CHECK( 0, pthread_create( &th, NULL, test_fct, &td ) ); - - /* Wait for the thread to be running */ - { - int ret = pthread_barrier_wait(&bar); - if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { - CHECK( 0, ret); - } else { - CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret ); - } - } - - /* Now cancel the thread */ - CHECK( 0, pthread_cancel( th ) ); - - /* Join it */ - CHECK( 0, pthread_join( th, NULL ) ); - - /* Do the same with the other function */ - td.ts = NULL; - - /* Create the thread */ - CHECK( 0, pthread_create( &th, NULL, test_fct, &td ) ); - - /* Wait for the thread to be running */ - { - int ret = pthread_barrier_wait(&bar); - if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { - CHECK( 0, ret); - } else { - CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret ); - } - } - - /* Now cancel the thread */ - CHECK( 0, pthread_cancel( th ) ); - - /* Join it */ - CHECK( 0, pthread_join( th, NULL ) ); - - /* Destroy the queue */ - CHECK( 0, fd_mq_del(&queue) ); - } - - /* Test the threashold function */ - { - struct mqueue * queue = NULL; - int i; - struct msg * msg = NULL; - - /* Create the queue */ - CHECK( 0, fd_mq_new(&queue) ); - - /* Prepare the test data */ - memset(&thrh_td, 0, sizeof(thrh_td)); - thrh_td.queue = queue; - - /* Set the thresholds for the queue */ - CHECK( 0, fd_mq_setthrhd ( queue, NULL, 6, thrh_cb_h, 4, thrh_cb_l ) ); - - /* Post 5 messages, no cb must be called. */ - for (i=0; i<5; i++) { - msg = msg1; - CHECK( 0, fd_mq_post(queue, &msg) ); - } /* 5 msg in queue */ - CHECK( 0, thrh_td.h_calls ); - CHECK( 0, thrh_td.l_calls ); - - /* Get all these messages, and check again */ - for (i=0; i<5; i++) { - CHECK( 0, fd_mq_get(queue, &msg) ); - } /* 0 msg in queue */ - CHECK( 0, thrh_td.h_calls ); - CHECK( 0, thrh_td.l_calls ); - - /* Now, post 6 messages, the high threashold */ - for (i=0; i<6; i++) { - msg = msg1; - CHECK( 0, fd_mq_post(queue, &msg) ); - } /* 6 msg in queue */ - CHECK( 1, thrh_td.h_calls ); - CHECK( 0, thrh_td.l_calls ); - - /* Remove 2 messages, to reach the low threshold */ - for (i=0; i<2; i++) { - CHECK( 0, fd_mq_get(queue, &msg) ); - } /* 4 msg in queue */ - CHECK( 1, thrh_td.h_calls ); - CHECK( 1, thrh_td.l_calls ); - - /* Come again at the high threshold */ - for (i=0; i<2; i++) { - msg = msg1; - CHECK( 0, fd_mq_post(queue, &msg) ); - } /* 6 msg in queue */ - CHECK( 2, thrh_td.h_calls ); - CHECK( 1, thrh_td.l_calls ); - - /* Suppose the queue continues to grow */ - for (i=0; i<6; i++) { - msg = msg1; - CHECK( 0, fd_mq_post(queue, &msg) ); - } /* 12 msg in queue */ - CHECK( 3, thrh_td.h_calls ); - CHECK( 1, thrh_td.l_calls ); - for (i=0; i<5; i++) { - msg = msg1; - CHECK( 0, fd_mq_post(queue, &msg) ); - } /* 17 msg in queue */ - CHECK( 3, thrh_td.h_calls ); - CHECK( 1, thrh_td.l_calls ); - - /* Now the queue goes back to 0 messages */ - for (i=0; i<17; i++) { - CHECK( 0, fd_mq_get(queue, &msg) ); - } /* 0 msg in queue */ - CHECK( 3, thrh_td.h_calls ); - CHECK( 3, thrh_td.l_calls ); - - /* We're done for this test */ - CHECK( 0, fd_mq_del(&queue) ); - } - - /* Delete the messages */ - CHECK( 0, fd_msg_free( msg1 ) ); - CHECK( 0, fd_msg_free( msg2 ) ); - CHECK( 0, fd_msg_free( msg3 ) ); - - /* That's all for the tests yet */ - PASSTEST(); -} diff -r e5af94b04946 -r 3e143f047f78 freeDiameter/tests/testqueues.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/tests/testqueues.c Fri Sep 18 18:54:07 2009 +0900 @@ -0,0 +1,423 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "tests.h" + +/* Structure for testing threshold function */ +static struct thrh_test { + struct fifo * queue; /* pointer to the queue */ + int h_calls; /* number of calls of h_cb */ + int l_calls; /* number of calls of l_cb */ +} thrh_td; + +/* Callbacks for threasholds test */ +void thrh_cb_h(struct fifo *queue, void **data) +{ + if (thrh_td.h_calls == thrh_td.l_calls) { + CHECK( NULL, *data ); + *data = &thrh_td; + } else { + CHECK( *data, &thrh_td ); + } + CHECK( queue, thrh_td.queue ); + + /* Update the count */ + thrh_td.h_calls ++; +} +void thrh_cb_l(struct fifo *queue, void **data) +{ + CHECK( 1, data ? 1 : 0 ); + CHECK( *data, &thrh_td ); + + /* Check the queue parameter is correct */ + CHECK( queue, thrh_td.queue ); + + /* Update the count */ + thrh_td.l_calls ++; + /* Cleanup the data ptr if needed */ + if (thrh_td.l_calls == thrh_td.h_calls) + *data = NULL; + /* done */ +} + + +/* Structure that is passed to the test function */ +struct test_data { + struct fifo * queue; /* pointer to the queue */ + pthread_barrier_t * bar; /* if not NULL, barrier to synchronize before getting messages */ + struct timespec * ts; /* if not NULL, use a timedget instead of a get */ + int nbr; /* number of messages to retrieve from the queue */ +}; + +/* The test function, to be threaded */ +static void * test_fct(void * data) +{ + int ret = 0, i; + struct msg * msg = NULL; + struct test_data * td = (struct test_data *) data; + + if (td->bar != NULL) { + ret = pthread_barrier_wait(td->bar); + if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { + CHECK( 0, ret); + } else { + CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret); /* just for the traces */ + } + } + + for (i=0; i< td->nbr; i++) { + if (td->ts != NULL) { + CHECK( 0, fd_fifo_timedget(td->queue, &msg, td->ts) ); + } else { + CHECK( 0, fd_fifo_get(td->queue, &msg) ); + } + } + + return NULL; +} + + +/* Main test routine */ +int main(int argc, char *argv[]) +{ + struct timespec ts; + + struct msg * msg1 = NULL; + struct msg * msg2 = NULL; + struct msg * msg3 = NULL; + + /* First, initialize the daemon modules */ + INIT_FD(); + + /* Prolog: create the messages */ + { + struct dict_object * acr_model = NULL; + struct dict_object * cer_model = NULL; + struct dict_object * dwr_model = NULL; + + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &dwr_model, ENOENT ) ); + CHECK( 0, fd_msg_new ( acr_model, 0, &msg1 ) ); + CHECK( 0, fd_msg_new ( cer_model, 0, &msg2 ) ); + CHECK( 0, fd_msg_new ( dwr_model, 0, &msg3 ) ); + } + + /* Basic operation */ + { + struct fifo * queue = NULL; + int count; + struct msg * msg = NULL; + + /* Create the queue */ + CHECK( 0, fd_fifo_new(&queue) ); + + /* Check the count is 0 */ + CHECK( 0, fd_fifo_length(queue, &count) ); + CHECK( 0, count); + + /* Now enqueue */ + msg = msg1; + CHECK( 0, fd_fifo_post(queue, &msg) ); + msg = msg2; + CHECK( 0, fd_fifo_post(queue, &msg) ); + msg = msg3; + CHECK( 0, fd_fifo_post(queue, &msg) ); + + /* Check the count is 3 */ + CHECK( 0, fd_fifo_length(queue, &count) ); + CHECK( 3, count); + + /* Retrieve the first message using fd_fifo_get */ + CHECK( 0, fd_fifo_get(queue, &msg) ); + CHECK( msg1, msg); + CHECK( 0, fd_fifo_length(queue, &count) ); + CHECK( 2, count); + + /* Retrieve the second message using fd_fifo_timedget */ + CHECK(0, clock_gettime(CLOCK_REALTIME, &ts)); + ts.tv_sec += 1; /* Set the timeout to 1 second */ + CHECK( 0, fd_fifo_timedget(queue, &msg, &ts) ); + CHECK( msg2, msg); + CHECK( 0, fd_fifo_length(queue, &count) ); + CHECK( 1, count); + + /* Retrieve the third message using meq_tryget */ + CHECK( 0, fd_fifo_tryget(queue, &msg) ); + CHECK( msg3, msg); + CHECK( 0, fd_fifo_length(queue, &count) ); + CHECK( 0, count); + + /* Check that another meq_tryget does not block */ + CHECK( EWOULDBLOCK, fd_fifo_tryget(queue, &msg) ); + CHECK( 0, fd_fifo_length(queue, &count) ); + CHECK( 0, count); + + /* We're done for basic tests */ + CHECK( 0, fd_fifo_del(&queue) ); + } + + /* Test robustness, ensure no messages are lost */ + { +#define NBR_MSG 200 +#define NBR_THREADS 60 + struct fifo *queue = NULL; + pthread_barrier_t bar; + struct test_data td_1; + struct test_data td_2; + struct msg *msgs[NBR_MSG * NBR_THREADS * 2], *msg; + pthread_t thr [NBR_THREADS * 2]; + struct dict_object *dwr_model = NULL; + int count; + int i; + + /* Create the queue */ + CHECK( 0, fd_fifo_new(&queue) ); + + /* Create the barrier */ + CHECK( 0, pthread_barrier_init(&bar, NULL, NBR_THREADS * 2 + 1) ); + + /* Initialize the ts */ + CHECK(0, clock_gettime(CLOCK_REALTIME, &ts)); + ts.tv_sec += 2; /* Set the timeout to 2 second */ + + /* Create the messages */ + CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &dwr_model, ENOENT ) ); + for (i = 0; i < NBR_MSG * NBR_THREADS * 2; i++) { + CHECK( 0, fd_msg_new ( dwr_model, 0, &msgs[i] ) ); + } + + /* Initialize the test data structures */ + td_1.queue = queue; + td_1.bar = &bar; + td_1.ts = &ts; + td_1.nbr = NBR_MSG; + td_2.queue = queue; + td_2.bar = &bar; + td_2.ts = NULL; + td_2.nbr = NBR_MSG; + + /* Create the threads */ + for (i=0; i < NBR_THREADS * 2; i++) { + CHECK( 0, pthread_create( &thr[i], NULL, test_fct, (i & 1) ? &td_1 : &td_2 ) ); + } + + /* Synchronize everyone */ + { + int ret = pthread_barrier_wait(&bar); + if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { + CHECK( 0, ret); + } else { + CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret); /* for trace only */ + } + } + + /* Now post all the messages */ + for (i=0; i < NBR_MSG * NBR_THREADS * 2; i++) { + msg = msgs[i]; + CHECK( 0, fd_fifo_post(queue, &msg) ); + } + + /* Join all threads. This blocks if messages are lost... */ + for (i=0; i < NBR_THREADS * 2; i++) { + CHECK( 0, pthread_join( thr[i], NULL ) ); + } + + /* Check the count of the queue is back to 0 */ + CHECK( 0, fd_fifo_length(queue, &count) ); + CHECK( 0, count); + + /* Destroy this queue and the messages */ + CHECK( 0, fd_fifo_del(&queue) ); + for (i=0; i < NBR_MSG * NBR_THREADS * 2; i++) { + CHECK( 0, fd_msg_free( msgs[i] ) ); + } + } + + /* Test thread cancelation */ + { + struct fifo *queue = NULL; + pthread_barrier_t bar; + struct test_data td; + pthread_t th; + + /* Create the queue */ + CHECK( 0, fd_fifo_new(&queue) ); + + /* Create the barrier */ + CHECK( 0, pthread_barrier_init(&bar, NULL, 2) ); + + /* Initialize the ts */ + CHECK(0, clock_gettime(CLOCK_REALTIME, &ts)); + ts.tv_sec += 2; /* Set the timeout to 2 second */ + + /* Initialize the test data structures */ + td.queue = queue; + td.bar = &bar; + td.ts = &ts; + td.nbr = 1; + + /* Create the thread */ + CHECK( 0, pthread_create( &th, NULL, test_fct, &td ) ); + + /* Wait for the thread to be running */ + { + int ret = pthread_barrier_wait(&bar); + if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { + CHECK( 0, ret); + } else { + CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret ); + } + } + + /* Now cancel the thread */ + CHECK( 0, pthread_cancel( th ) ); + + /* Join it */ + CHECK( 0, pthread_join( th, NULL ) ); + + /* Do the same with the other function */ + td.ts = NULL; + + /* Create the thread */ + CHECK( 0, pthread_create( &th, NULL, test_fct, &td ) ); + + /* Wait for the thread to be running */ + { + int ret = pthread_barrier_wait(&bar); + if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { + CHECK( 0, ret); + } else { + CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret ); + } + } + + /* Now cancel the thread */ + CHECK( 0, pthread_cancel( th ) ); + + /* Join it */ + CHECK( 0, pthread_join( th, NULL ) ); + + /* Destroy the queue */ + CHECK( 0, fd_fifo_del(&queue) ); + } + + /* Test the threashold function */ + { + struct fifo * queue = NULL; + int i; + struct msg * msg = NULL; + + /* Create the queue */ + CHECK( 0, fd_fifo_new(&queue) ); + + /* Prepare the test data */ + memset(&thrh_td, 0, sizeof(thrh_td)); + thrh_td.queue = queue; + + /* Set the thresholds for the queue */ + CHECK( 0, fd_fifo_setthrhd ( queue, NULL, 6, thrh_cb_h, 4, thrh_cb_l ) ); + + /* Post 5 messages, no cb must be called. */ + for (i=0; i<5; i++) { + msg = msg1; + CHECK( 0, fd_fifo_post(queue, &msg) ); + } /* 5 msg in queue */ + CHECK( 0, thrh_td.h_calls ); + CHECK( 0, thrh_td.l_calls ); + + /* Get all these messages, and check again */ + for (i=0; i<5; i++) { + CHECK( 0, fd_fifo_get(queue, &msg) ); + } /* 0 msg in queue */ + CHECK( 0, thrh_td.h_calls ); + CHECK( 0, thrh_td.l_calls ); + + /* Now, post 6 messages, the high threashold */ + for (i=0; i<6; i++) { + msg = msg1; + CHECK( 0, fd_fifo_post(queue, &msg) ); + } /* 6 msg in queue */ + CHECK( 1, thrh_td.h_calls ); + CHECK( 0, thrh_td.l_calls ); + + /* Remove 2 messages, to reach the low threshold */ + for (i=0; i<2; i++) { + CHECK( 0, fd_fifo_get(queue, &msg) ); + } /* 4 msg in queue */ + CHECK( 1, thrh_td.h_calls ); + CHECK( 1, thrh_td.l_calls ); + + /* Come again at the high threshold */ + for (i=0; i<2; i++) { + msg = msg1; + CHECK( 0, fd_fifo_post(queue, &msg) ); + } /* 6 msg in queue */ + CHECK( 2, thrh_td.h_calls ); + CHECK( 1, thrh_td.l_calls ); + + /* Suppose the queue continues to grow */ + for (i=0; i<6; i++) { + msg = msg1; + CHECK( 0, fd_fifo_post(queue, &msg) ); + } /* 12 msg in queue */ + CHECK( 3, thrh_td.h_calls ); + CHECK( 1, thrh_td.l_calls ); + for (i=0; i<5; i++) { + msg = msg1; + CHECK( 0, fd_fifo_post(queue, &msg) ); + } /* 17 msg in queue */ + CHECK( 3, thrh_td.h_calls ); + CHECK( 1, thrh_td.l_calls ); + + /* Now the queue goes back to 0 messages */ + for (i=0; i<17; i++) { + CHECK( 0, fd_fifo_get(queue, &msg) ); + } /* 0 msg in queue */ + CHECK( 3, thrh_td.h_calls ); + CHECK( 3, thrh_td.l_calls ); + + /* We're done for this test */ + CHECK( 0, fd_fifo_del(&queue) ); + } + + /* Delete the messages */ + CHECK( 0, fd_msg_free( msg1 ) ); + CHECK( 0, fd_msg_free( msg2 ) ); + CHECK( 0, fd_msg_free( msg3 ) ); + + /* That's all for the tests yet */ + PASSTEST(); +} diff -r e5af94b04946 -r 3e143f047f78 freeDiameter/tests/tests.h --- a/freeDiameter/tests/tests.h Fri Sep 04 18:05:25 2009 +0900 +++ b/freeDiameter/tests/tests.h Fri Sep 18 18:54:07 2009 +0900 @@ -74,6 +74,8 @@ } static int test_verbo = 0; +static struct fd_config conf; +struct fd_config * fd_g_config = &conf; /* Define the standard check routines */ #define CHECK( _val, _assert ){ \ @@ -96,12 +98,13 @@ } /* Minimum inits */ -#define INIT_FD() { \ - CHECK( 0, fd_lib_init() ); \ - fd_log_threadname(basename(__FILE__)); \ - CHECK( 0, fd_dict_init(&fd_g_dict) ); \ - CHECK( 0, fd_dict_base_protocol(fd_g_dict) ); \ - parse_cmdline(argc, argv); \ +#define INIT_FD() { \ + memset(fd_g_config, 0, sizeof(struct fd_config)); \ + CHECK( 0, fd_lib_init() ); \ + fd_log_threadname(basename(__FILE__)); \ + CHECK( 0, fd_conf_init() ); \ + CHECK( 0, fd_dict_base_protocol(fd_g_config->g_dict) ); \ + parse_cmdline(argc, argv); \ } static inline void parse_cmdline(int argc, char * argv[]) { diff -r e5af94b04946 -r 3e143f047f78 include/freeDiameter/CMakeLists.txt --- a/include/freeDiameter/CMakeLists.txt Fri Sep 04 18:05:25 2009 +0900 +++ b/include/freeDiameter/CMakeLists.txt Fri Sep 18 18:54:07 2009 +0900 @@ -71,6 +71,9 @@ # malloc.h ? CHECK_INCLUDE_FILES (malloc.h HAVE_MALLOC_H) +# signalent.h ? -- found in strace distrib; just for nice signal names... +CHECK_INCLUDE_FILES (signalent.h HAVE_SIGNALENT_H) + # The default configuration file name IF (NOT DEFAULT_CONF_FILE) SET(DEFAULT_CONF_FILE "freeDiameter.conf") diff -r e5af94b04946 -r 3e143f047f78 include/freeDiameter/extension.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/freeDiameter/extension.h Fri Sep 18 18:54:07 2009 +0900 @@ -0,0 +1,63 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#ifndef _EXTENSION_H +#define _EXTENSION_H + +/* Include definition of freeDiameter API */ +#include +#include + +/* Macro that define the entry point of the extension */ +#define EXTENSION_ENTRY(_name, _function) \ +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)) { \ + fprintf(stderr, "This extension (" _name ") was compiled for a different version of freeDiameter.\n"); \ + TRACE_DEBUG(INFO, "daemon %d.%d != ext %d.%d", \ + major, minor, \ + FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR); \ + return EINVAL; \ + } \ + if (extension_loaded) { \ + fprintf(stderr, "Extension (" _name ") cannot be loaded twice!\n"); \ + return ENOTSUP; \ + } \ + extension_loaded++; \ + return (_function)(conffile); \ +} + +#endif /* _EXTENSION_H */ diff -r e5af94b04946 -r 3e143f047f78 include/freeDiameter/freeDiameter-host.h.in --- a/include/freeDiameter/freeDiameter-host.h.in Fri Sep 04 18:05:25 2009 +0900 +++ b/include/freeDiameter/freeDiameter-host.h.in Fri Sep 18 18:54:07 2009 +0900 @@ -39,16 +39,31 @@ #cmakedefine HAVE_NTOHLL #cmakedefine HAVE_MALLOC_H +#cmakedefine HAVE_SIGNALENT_H #cmakedefine HOST_BIG_ENDIAN @HOST_BIG_ENDIAN@ #cmakedefine DISABLE_SCTP -#cmakedefine PROJECT_NAME "@PROJECT_NAME@" -#cmakedefine CMAKE_PROJECT_NAME "@CMAKE_PROJECT_NAME@" -#cmakedefine PROJECT_VERSION "@PROJECT_VERSION@" -#cmakedefine PROJECT_COPYRIGHT "@PROJECT_COPYRIGHT@" +#cmakedefine 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*/ +/* HG_VERSION */ +/* PACKAGE_HG_REVISION */ +#cmakedefine FD_PROJECT_COPYRIGHT "@FD_PROJECT_COPYRIGHT@" #cmakedefine DEFAULT_CONF_FILE "@DEFAULT_CONF_FILE@" + #endif /* FD_IS_CONFIG */ diff -r e5af94b04946 -r 3e143f047f78 include/freeDiameter/freeDiameter.h --- a/include/freeDiameter/freeDiameter.h Fri Sep 04 18:05:25 2009 +0900 +++ b/include/freeDiameter/freeDiameter.h Fri Sep 18 18:54:07 2009 +0900 @@ -40,9 +40,77 @@ #include -/* The global dictionary */ -extern struct dictionary * fd_g_dict; +/* Structure to hold the configuration of the freeDiameter daemon */ +struct fd_config { + int eyec; /* Eye catcher: EYEC_CONFIG */ + char *conf_file; /* Configuration file to parse, default is DEFAULT_CONF_FILE */ + + char *diam_id; /* Diameter Identity of the local peer (FQDN -- UTF-8) */ + size_t diam_id_len; /* length of the previous string */ + char *diam_realm; /* Diameter realm of the local peer, default to realm part of diam_id */ + size_t diam_realm_len;/* length of the previous string */ + + uint16_t loc_port; /* the local port for legacy Diameter (default: 3868) in host byte order */ + uint16_t loc_port_tls; /* the local port for Diameter/TLS (default: 3869) in host byte order */ + uint16_t loc_sctp_str; /* default max number of streams for SCTP associations (def: 30) */ + struct fd_list loc_endpoints; /* the local endpoints to bind the server to. list of struct fd_endpoint. default is empty (bind all) */ + struct { + 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) */ + unsigned no_fwd : 1; /* the peer does not relay messages (0xffffff app id) */ + } flags; + + unsigned int timer_tc; /* The value in seconds of the default Tc timer */ + unsigned int timer_tw; /* The value in seconds of the default Tw timer */ + + uint32_t or_state_id; /* The value to use in Origin-State-Id, default to random value */ + struct dictionary *g_dict; /* pointer to the global dictionary */ + struct fifo *g_fifo_main; /* FIFO queue of events in the daemon main (struct fd_event items) */ +}; + +#define EYEC_CONFIG 0xC011F16 +/* The pointer to access the global configuration, initalized in main */ +extern struct fd_config *fd_g_config; + +/* Endpoints */ +struct fd_endpoint { + struct fd_list chain; /* link in loc_endpoints list */ + sSS ss; /* the socket information. */ +}; + +/* Events */ +struct fd_event { + int code; /* codespace depends on the queue */ + void *data; +}; + +/* send an event */ +static __inline__ int fd_event_send(struct fifo *queue, int code, void * data) +{ + struct fd_event * ev; + CHECK_MALLOC( ev = malloc(sizeof(struct fd_event)) ); + ev->code = code; + ev->data = data; + CHECK_FCT( fd_fifo_post(queue, &ev) ); + return 0; +} +/* receive an event */ +static __inline__ int fd_event_get(struct fifo *queue, int *code, void ** data) +{ + struct fd_event * ev; + CHECK_FCT( fd_fifo_get(queue, &ev) ); + if (code) + *code = ev->code; + if (data) + *data = ev->data; + free(ev); + return 0; +} /***************************************/ /* Sending a message on the network */ diff -r e5af94b04946 -r 3e143f047f78 include/freeDiameter/libfreeDiameter.h --- a/include/freeDiameter/libfreeDiameter.h Fri Sep 04 18:05:25 2009 +0900 +++ b/include/freeDiameter/libfreeDiameter.h Fri Sep 18 18:54:07 2009 +0900 @@ -36,10 +36,19 @@ /* 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 * - * It provides the tools to manipulate Diameter messages and related data. - * - * This file should always be included as #include + * The file contains the following parts: + * DEBUG + * MACROS + * THREADS + * LISTS + * DICTIONARY + * SESSIONS + * MESSAGES + * DISPATCH + * QUEUES */ #ifndef _LIBFREEDIAMETER_H @@ -296,10 +305,10 @@ #define sSA4 struct sockaddr_in #define sSA6 struct sockaddr_in6 -/* Dump one sockaddr */ -#define sSA_DUMP( level, text, sa ) { \ +/* Dump one sockaddr Node information */ +#define sSA_DUMP_NODE( sa, flag ) { \ sSA * __sa = (sSA *)(sa); \ - char *__str, __addrbuf[INET6_ADDRSTRLEN]; \ + char __addrbuf[INET6_ADDRSTRLEN]; \ if (__sa) { \ int __rc = getnameinfo(__sa, \ sizeof(sSS), \ @@ -307,16 +316,16 @@ sizeof(__addrbuf), \ NULL, \ 0, \ - 0); \ + flag); \ if (__rc) \ - __str = (char *)gai_strerror(__rc); \ + fd_log_debug((char *)gai_strerror(__rc)); \ else \ - __str = &__addrbuf[0]; \ + fd_log_debug(&__addrbuf[0]); \ } else { \ - __str = "(NULL / ANY)"; \ + fd_log_debug("(NULL / ANY)"); \ } \ - TRACE_DEBUG(level, text "%s", __str); \ } +/* if needed, add sSA_DUMP_SERVICE */ /* The sockaddr length of a sSS structure */ #define sSSlen( _ss_ ) \ @@ -2274,65 +2283,65 @@ /*============================================================*/ -/* MESSAGE QUEUES */ +/* QUEUES */ /*============================================================*/ -/* Management of queues of messages */ +/* Management of FIFO queues of elements */ -/* A message queue is an opaque object */ -struct mqueue; +/* A queue is an opaque object */ +struct fifo; /* - * FUNCTION: fd_mq_new + * FUNCTION: fd_fifo_new * * PARAMETERS: - * queue : Upon success, a pointer to the new message queue is saved here. + * queue : Upon success, a pointer to the new queue is saved here. * * DESCRIPTION: - * Create a new empty message queue. + * Create a new empty queue. * * RETURN VALUE : - * 0 : The message queue has been initialized successfully. + * 0 : The queue has been initialized successfully. * EINVAL : The parameter is invalid. * ENOMEM : Not enough memory to complete the creation. */ -int fd_mq_new ( struct mqueue ** queue ); +int fd_fifo_new ( struct fifo ** queue ); /* - * FUNCTION: fd_mq_del + * FUNCTION: fd_fifo_del * * PARAMETERS: - * queue : Pointer to an empty message queue to delete. + * queue : Pointer to an empty queue to delete. * * DESCRIPTION: - * Destroys a message queue. This is only possible if no thread is waiting for a message, + * Destroys a queue. This is only possible if no thread is waiting for an element, * and the queue is empty. * * RETURN VALUE: - * 0 : The message queue has been destroyed successfully. + * 0 : The queue has been destroyed successfully. * EINVAL : The parameter is invalid. */ -int fd_mq_del ( struct mqueue ** queue ); +int fd_fifo_del ( struct fifo ** queue ); /* - * FUNCTION: fd_mq_length + * FUNCTION: fd_fifo_length * * PARAMETERS: - * queue : The queue from which to retrieve the length. - * length : Upon success, the current number of messages in the queue is stored here. + * queue : The queue from which to retrieve the number of elements. + * length : Upon success, the current number of elements in the queue is stored here. * * DESCRIPTION: - * Retrieve the number of messages pending in a queue. + * Retrieve the number of elements in a queue. * * RETURN VALUE: * 0 : The length of the queue has been written. * EINVAL : A parameter is invalid. */ -int fd_mq_length ( struct mqueue * queue, int * length ); -int fd_mq_length_noerr ( struct mqueue * queue ); /* alternate with no error checking */ +int fd_fifo_length ( struct fifo * queue, int * length ); +int fd_fifo_length_noerr ( struct fifo * queue ); /* no error checking version */ /* - * FUNCTION: fd_mq_setthrhd + * FUNCTION: fd_fifo_setthrhd * * PARAMETERS: * queue : The queue for which the thresholds are being set. @@ -2344,98 +2353,106 @@ * * DESCRIPTION: * This function allows to adjust the number of producer / consumer threads of a queue. - * If the consumer are slower than the producers, the number of messages in the queue increase. + * 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 may implement a limit on the number of consumers that can be created) + * (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 continue to reduce, l_cb is again called at (N-2)*high + low, + * 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_mq_post or fd_mq_get. Their operation should be quick. + * 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_mq_setthrhd ( struct mqueue * queue, void * data, uint16_t high, void (*h_cb)(struct mqueue *, void **), uint16_t low, void (*l_cb)(struct mqueue *, void **) ); +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_mq_post + * FUNCTION: fd_fifo_post * * PARAMETERS: - * queue : The queue in which the message must be posted. - * msg : The message that is put in the queue. + * queue : The queue in which the element must be posted. + * item : The element that is put in the queue. * * DESCRIPTION: - * A message is added in a queue. Messages are retrieved from the queue (in FIFO order) - * with the fd_mq_get, fd_mq_tryget, or fd_mq_timedget functions. + * 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 message is queued. + * 0 : The element is queued. * EINVAL : A parameter is invalid. * ENOMEM : Not enough memory to complete the operation. */ -int fd_mq_post ( struct mqueue * queue, struct msg ** msg ); +int fd_fifo_post_int ( struct fifo * queue, void ** item ); +#define fd_fifo_post(queue, item) \ + fd_fifo_post_int((queue), (void *)(item)) /* - * FUNCTION: fd_mq_get + * FUNCTION: fd_fifo_get * * PARAMETERS: - * queue : The queue from which the message must be retrieved. - * msg : On return, the first message of the queue is stored here. + * 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 a message from a queue. If the queue is empty, the function will block the - * thread until a new message is posted to the queue, or until the thread is canceled (in which case the + * 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 message has been retrieved. + * 0 : A new element has been retrieved. * EINVAL : A parameter is invalid. */ -int fd_mq_get ( struct mqueue * queue, struct msg ** msg ); +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_mq_tryget + * FUNCTION: fd_fifo_tryget * * PARAMETERS: - * queue : The queue from which the message must be retrieved. + * queue : The queue from which the element must be retrieved. * msg : On return, the message is stored here. * * DESCRIPTION: - * This function is similar to fd_mq_get, except that it will not block if + * 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 message has been retrieved. + * 0 : A new element has been retrieved. * EINVAL : A parameter is invalid. * EWOULDBLOCK : The queue was empty. */ -int fd_mq_tryget ( struct mqueue * queue, struct msg ** msg ); +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_mq_timedget + * FUNCTION: fd_fifo_timedget * * PARAMETERS: - * queue : The queue from which the message must be retrieved. - * msg : On return, the message is stored here. - * abstime : the absolute time until which we allow waiting for a message. + * 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_mq_get, except that it will block if the queue is empty + * 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 message has been retrieved. + * 0 : A new item has been retrieved. * EINVAL : A parameter is invalid. - * ETIMEDOUT : The time out has passed and no message has been received. + * ETIMEDOUT : The time out has passed and no item has been received. */ -int fd_mq_timedget ( struct mqueue * queue, struct msg ** msg, const struct timespec *abstime ); +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)) #endif /* _LIBFREEDIAMETER_H */ diff -r e5af94b04946 -r 3e143f047f78 libfreeDiameter/CMakeLists.txt --- a/libfreeDiameter/CMakeLists.txt Fri Sep 04 18:05:25 2009 +0900 +++ b/libfreeDiameter/CMakeLists.txt Fri Sep 18 18:54:07 2009 +0900 @@ -1,8 +1,6 @@ # Name of the subproject Project("libfreeDiameter" C) -SET(PROJECT_COPYRIGHT "Copyright (c) 2008-2009, WIDE Project (www.wide.ad.jp) and NICT (www.nict.go.jp)") - # List of source files for the library SET(LFD_SRC libfD.h @@ -12,7 +10,7 @@ lists.c log.c messages.c - mqueues.c + queues.c sessions.c ) diff -r e5af94b04946 -r 3e143f047f78 libfreeDiameter/mqueues.c --- a/libfreeDiameter/mqueues.c Fri Sep 04 18:05:25 2009 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,394 +0,0 @@ -/********************************************************************************************************* -* Software License Agreement (BSD License) * -* Author: Sebastien Decugis * -* * -* Copyright (c) 2008, WIDE Project and NICT * -* All rights reserved. * -* * -* Redistribution and use of this software in source and binary forms, with or without modification, are * -* permitted provided that the following conditions are met: * -* * -* * Redistributions of source code must retain the above * -* copyright notice, this list of conditions and the * -* following disclaimer. * -* * -* * Redistributions in binary form must reproduce the above * -* copyright notice, this list of conditions and the * -* following disclaimer in the documentation and/or other * -* materials provided with the distribution. * -* * -* * Neither the name of the WIDE Project or NICT nor the * -* names of its contributors may be used to endorse or * -* promote products derived from this software without * -* specific prior written permission of WIDE Project and * -* NICT. * -* * -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * -* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * -* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * -* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -*********************************************************************************************************/ - -/* Messages queues module. - * - * The threads that call these functions must be in the cancellation state PTHREAD_CANCEL_ENABLE and type PTHREAD_CANCEL_DEFERRED. - * This is the default state and type on thread creation. - * - * In order to destroy properly a queue, the application must: - * -> shutdown any process that can add into the queue first. - * -> pthread_cancel any thread that could be waiting on the queue. - * -> consume any message that is in the queue, using meq_tryget. - * -> then destroy the queue using meq_del. - */ - -#include "libfD.h" - -/* Definition of a message queue object */ -struct mqueue { - int eyec; /* An eye catcher, also used to check a queue is valid. MQ_EYEC */ - - pthread_mutex_t mtx; /* Mutex protecting this queue */ - pthread_cond_t cond; /* condition variable of the list */ - - struct fd_list list; /* sentinel for the list of messages */ - int count; /* number of objects in the list */ - int thrs; /* number of threads waiting for a new message (when count is 0) */ - - uint16_t high; /* High level threshold (see libfreeDiameter.h for details) */ - uint16_t low; /* Low level threshhold */ - void *data; /* Opaque pointer for threshold callbacks */ - void (*h_cb)(struct mqueue *, void **); /* The callbacks */ - void (*l_cb)(struct mqueue *, void **); - int highest;/* The highest count value for which h_cb has been called */ -}; - -/* The eye catcher value */ -#define MQ_EYEC 0xe7ec1130 - -/* Macro to check a pointer */ -#define CHECK_QUEUE( _queue ) (( (_queue) != NULL) && ( (_queue)->eyec == MQ_EYEC) ) - - -/* Create a new message queue */ -int fd_mq_new ( struct mqueue ** queue ) -{ - struct mqueue * new; - - TRACE_ENTRY( "%p", queue ); - - CHECK_PARAMS( queue ); - - /* Create a new object */ - CHECK_MALLOC( new = malloc (sizeof (struct mqueue) ) ); - - /* Initialize the content */ - memset(new, 0, sizeof(struct mqueue)); - - new->eyec = MQ_EYEC; - CHECK_POSIX( pthread_mutex_init(&new->mtx, NULL) ); - CHECK_POSIX( pthread_cond_init(&new->cond, NULL) ); - - fd_list_init(&new->list, NULL); - - /* We're done */ - *queue = new; - return 0; -} - -/* Delete a message queue. It must be unused. */ -int fd_mq_del ( struct mqueue ** queue ) -{ - struct mqueue * q; - - TRACE_ENTRY( "%p", queue ); - - CHECK_PARAMS( queue && CHECK_QUEUE( *queue ) ); - - q = *queue; - - CHECK_POSIX( pthread_mutex_lock( &q->mtx ) ); - - if ((q->count != 0) || (q->thrs != 0) || (q->data != NULL)) { - TRACE_DEBUG(INFO, "The queue cannot be destroyed (%d, %d, %p)", q->count, q->thrs, q->data); - CHECK_POSIX_DO( pthread_mutex_unlock( &q->mtx ), /* no fallback */ ); - return EINVAL; - } - - /* sanity check */ - ASSERT(FD_IS_LIST_EMPTY(&q->list)); - - /* Ok, now invalidate the queue */ - q->eyec = 0xdead; - - /* And destroy it */ - CHECK_POSIX( pthread_mutex_unlock( &q->mtx ) ); - - CHECK_POSIX( pthread_cond_destroy( &q->cond ) ); - - CHECK_POSIX( pthread_mutex_destroy( &q->mtx ) ); - - free(q); - *queue = NULL; - - return 0; -} - -/* Get the length of the queue */ -int fd_mq_length ( struct mqueue * queue, int * length ) -{ - TRACE_ENTRY( "%p %p", queue, length ); - - /* Check the parameters */ - CHECK_PARAMS( CHECK_QUEUE( queue ) && length ); - - /* lock the queue */ - CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); - - /* Retrieve the count */ - *length = queue->count; - - /* Unlock */ - CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); - - /* Done */ - return 0; -} - -/* alternate version with no error checking */ -int fd_mq_length_noerr ( struct mqueue * queue ) -{ - if ( !CHECK_QUEUE( queue ) ) - return 0; - - return queue->count; /* Let's hope it's read atomically, since we are not locking... */ -} - -/* Set the thresholds of the queue */ -int fd_mq_setthrhd ( struct mqueue * queue, void * data, uint16_t high, void (*h_cb)(struct mqueue *, void **), uint16_t low, void (*l_cb)(struct mqueue *, void **) ) -{ - TRACE_ENTRY( "%p %p %hu %p %hu %p", queue, data, high, h_cb, low, l_cb ); - - /* Check the parameters */ - CHECK_PARAMS( CHECK_QUEUE( queue ) && (high > low) && (queue->data == NULL) ); - - /* lock the queue */ - CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); - - /* Save the values */ - queue->high = high; - queue->low = low; - queue->data = data; - queue->h_cb = h_cb; - queue->l_cb = l_cb; - - /* Unlock */ - CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); - - /* Done */ - return 0; -} - -/* Post a new message in the queue */ -int fd_mq_post ( struct mqueue * queue, struct msg ** msg ) -{ - struct fd_list * new; - int call_cb = 0; - - TRACE_ENTRY( "%p %p", queue, msg ); - - /* Check the parameters */ - CHECK_PARAMS( CHECK_QUEUE( queue ) && msg && *msg ); - - /* Create a new list item */ - CHECK_MALLOC( new = malloc (sizeof (struct fd_list)) ); - - fd_list_init(new, *msg); - *msg = NULL; - - /* lock the queue */ - CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); - - /* Add the new message at the end */ - fd_list_insert_before( &queue->list, new); - queue->count++; - if (queue->high && ((queue->count % queue->high) == 0)) { - call_cb = 1; - queue->highest = queue->count; - } - - /* Signal if threads are asleep */ - if (queue->thrs > 0) { - CHECK_POSIX( pthread_cond_signal(&queue->cond) ); - } - - /* Unlock */ - CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); - - /* Call high-watermark cb as needed */ - if (call_cb && queue->h_cb) - (*queue->h_cb)(queue, &queue->data); - - /* Done */ - return 0; -} - -/* Pop the first message from the queue */ -static struct msg * mq_pop(struct mqueue * queue) -{ - struct msg * ret = NULL; - struct fd_list * li; - - ASSERT( ! FD_IS_LIST_EMPTY(&queue->list) ); - - fd_list_unlink(li = queue->list.next); - queue->count--; - ret = (struct msg *)(li->o); - free(li); - - return ret; -} - -/* Check if the low watermark callback must be called. */ -static int test_l_cb(struct mqueue * queue) -{ - if ((queue->high == 0) || (queue->low == 0) || (queue->l_cb == 0)) - return 0; - - if (((queue->count % queue->high) == queue->low) && (queue->highest > queue->count)) { - queue->highest -= queue->high; - return 1; - } - - return 0; -} - -/* Try poping a message */ -int fd_mq_tryget ( struct mqueue * queue, struct msg ** msg ) -{ - int wouldblock = 0; - int call_cb = 0; - - TRACE_ENTRY( "%p %p", queue, msg ); - - /* Check the parameters */ - CHECK_PARAMS( CHECK_QUEUE( queue ) && msg ); - - /* lock the queue */ - CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); - - /* Check queue status */ - if (queue->count > 0) { - /* There are messages in the queue, so pick the first one */ - *msg = mq_pop(queue); - call_cb = test_l_cb(queue); - } else { - wouldblock = 1; - *msg = NULL; - } - - /* Unlock */ - CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); - - /* Call low watermark callback as needed */ - if (call_cb) - (*queue->l_cb)(queue, &queue->data); - - /* Done */ - return wouldblock ? EWOULDBLOCK : 0; -} - -/* This handler is called when a thread is blocked on a queue, and cancelled */ -static void mq_cleanup(void * queue) -{ - struct mqueue * q = (struct mqueue *)queue; - TRACE_ENTRY( "%p", queue ); - - /* Check the parameter */ - if ( ! CHECK_QUEUE( q )) { - TRACE_DEBUG(INFO, "Invalid queue, skipping handler"); - return; - } - - /* The thread has been cancelled, therefore it does not wait on the queue anymore */ - q->thrs--; - - /* Now unlock the queue, and we're done */ - CHECK_POSIX_DO( pthread_mutex_unlock( &q->mtx ), /* nothing */ ); - - /* End of cleanup handler */ - return; -} - -/* The internal function for meq_timedget and meq_get */ -static int mq_tget ( struct mqueue * queue, struct msg ** msg, int istimed, const struct timespec *abstime) -{ - int timedout = 0; - int call_cb = 0; - - /* Check the parameters */ - CHECK_PARAMS( CHECK_QUEUE( queue ) && msg && (abstime || !istimed) ); - - /* Initialize the msg value */ - *msg = NULL; - - /* lock the queue */ - CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); - -awaken: - /* Check queue status */ - if (queue->count > 0) { - /* There are messages in the queue, so pick the first one */ - *msg = mq_pop(queue); - call_cb = test_l_cb(queue); - } else { - int ret = 0; - /* We have to wait for a new message */ - queue->thrs++ ; - pthread_cleanup_push( mq_cleanup, queue); - if (istimed) { - ret = pthread_cond_timedwait( &queue->cond, &queue->mtx, abstime ); - } else { - ret = pthread_cond_wait( &queue->cond, &queue->mtx ); - } - pthread_cleanup_pop(0); - queue->thrs-- ; - if (ret == 0) - goto awaken; /* test for spurious wake-ups */ - - if (istimed && (ret == ETIMEDOUT)) { - timedout = 1; - } else { - /* Unexpected error condition (means we need to debug) */ - ASSERT( ret == 0 /* never true */ ); - } - } - - /* Unlock */ - CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); - - /* Call low watermark callback as needed */ - if (call_cb) - (*queue->l_cb)(queue, &queue->data); - - /* Done */ - return timedout ? ETIMEDOUT : 0; -} - -/* Get the next available message, block until there is one */ -int fd_mq_get ( struct mqueue * queue, struct msg ** msg ) -{ - TRACE_ENTRY( "%p %p", queue, msg ); - return mq_tget(queue, msg, 0, NULL); -} - -/* Get the next available message, block until there is one, or the timeout expires */ -int fd_mq_timedget ( struct mqueue * queue, struct msg ** msg, const struct timespec *abstime ) -{ - TRACE_ENTRY( "%p %p %p", queue, msg, abstime ); - return mq_tget(queue, msg, 1, abstime); -} - diff -r e5af94b04946 -r 3e143f047f78 libfreeDiameter/queues.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfreeDiameter/queues.c Fri Sep 18 18:54:07 2009 +0900 @@ -0,0 +1,394 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2008, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +/* FIFO queues module. + * + * The threads that call these functions must be in the cancellation state PTHREAD_CANCEL_ENABLE and type PTHREAD_CANCEL_DEFERRED. + * This is the default state and type on thread creation. + * + * In order to destroy properly a queue, the application must: + * -> shutdown any process that can add into the queue first. + * -> pthread_cancel any thread that could be waiting on the queue. + * -> consume any element that is in the queue, using fd_qu_tryget_int. + * -> then destroy the queue using fd_mq_del. + */ + +#include "libfD.h" + +/* Definition of a FIFO queue object */ +struct fifo { + int eyec; /* An eye catcher, also used to check a queue is valid. FIFO_EYEC */ + + pthread_mutex_t mtx; /* Mutex protecting this queue */ + pthread_cond_t cond; /* condition variable of the list */ + + struct fd_list list; /* sentinel for the list of elements */ + int count; /* number of objects in the list */ + int thrs; /* number of threads waiting for a new element (when count is 0) */ + + uint16_t high; /* High level threshold (see libfreeDiameter.h for details) */ + uint16_t low; /* Low level threshhold */ + void *data; /* Opaque pointer for threshold callbacks */ + void (*h_cb)(struct fifo *, void **); /* The callbacks */ + void (*l_cb)(struct fifo *, void **); + int highest;/* The highest count value for which h_cb has been called */ +}; + +/* The eye catcher value */ +#define FIFO_EYEC 0xe7ec1130 + +/* Macro to check a pointer */ +#define CHECK_FIFO( _queue ) (( (_queue) != NULL) && ( (_queue)->eyec == FIFO_EYEC) ) + + +/* Create a new queue */ +int fd_fifo_new ( struct fifo ** queue ) +{ + struct fifo * new; + + TRACE_ENTRY( "%p", queue ); + + CHECK_PARAMS( queue ); + + /* Create a new object */ + CHECK_MALLOC( new = malloc (sizeof (struct fifo) ) ); + + /* Initialize the content */ + memset(new, 0, sizeof(struct fifo)); + + new->eyec = FIFO_EYEC; + CHECK_POSIX( pthread_mutex_init(&new->mtx, NULL) ); + CHECK_POSIX( pthread_cond_init(&new->cond, NULL) ); + + fd_list_init(&new->list, NULL); + + /* We're done */ + *queue = new; + return 0; +} + +/* Delete a queue. It must be unused. */ +int fd_fifo_del ( struct fifo ** queue ) +{ + struct fifo * q; + + TRACE_ENTRY( "%p", queue ); + + CHECK_PARAMS( queue && CHECK_FIFO( *queue ) ); + + q = *queue; + + CHECK_POSIX( pthread_mutex_lock( &q->mtx ) ); + + if ((q->count != 0) || (q->thrs != 0) || (q->data != NULL)) { + TRACE_DEBUG(INFO, "The queue cannot be destroyed (%d, %d, %p)", q->count, q->thrs, q->data); + CHECK_POSIX_DO( pthread_mutex_unlock( &q->mtx ), /* no fallback */ ); + return EINVAL; + } + + /* sanity check */ + ASSERT(FD_IS_LIST_EMPTY(&q->list)); + + /* Ok, now invalidate the queue */ + q->eyec = 0xdead; + + /* And destroy it */ + CHECK_POSIX( pthread_mutex_unlock( &q->mtx ) ); + + CHECK_POSIX( pthread_cond_destroy( &q->cond ) ); + + CHECK_POSIX( pthread_mutex_destroy( &q->mtx ) ); + + free(q); + *queue = NULL; + + return 0; +} + +/* Get the length of the queue */ +int fd_fifo_length ( struct fifo * queue, int * length ) +{ + TRACE_ENTRY( "%p %p", queue, length ); + + /* Check the parameters */ + CHECK_PARAMS( CHECK_FIFO( queue ) && length ); + + /* lock the queue */ + CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); + + /* Retrieve the count */ + *length = queue->count; + + /* Unlock */ + CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); + + /* Done */ + return 0; +} + +/* alternate version with no error checking */ +int fd_fifo_length_noerr ( struct fifo * queue ) +{ + if ( !CHECK_FIFO( queue ) ) + return 0; + + return queue->count; /* Let's hope it's read atomically, since we are not locking... */ +} + +/* Set the thresholds of the queue */ +int fd_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 **) ) +{ + TRACE_ENTRY( "%p %p %hu %p %hu %p", queue, data, high, h_cb, low, l_cb ); + + /* Check the parameters */ + CHECK_PARAMS( CHECK_FIFO( queue ) && (high > low) && (queue->data == NULL) ); + + /* lock the queue */ + CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); + + /* Save the values */ + queue->high = high; + queue->low = low; + queue->data = data; + queue->h_cb = h_cb; + queue->l_cb = l_cb; + + /* Unlock */ + CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); + + /* Done */ + return 0; +} + +/* Post a new item in the queue */ +int fd_fifo_post_int ( struct fifo * queue, void ** item ) +{ + struct fd_list * new; + int call_cb = 0; + + TRACE_ENTRY( "%p %p", queue, item ); + + /* Check the parameters */ + CHECK_PARAMS( CHECK_FIFO( queue ) && item && *item ); + + /* Create a new list item */ + CHECK_MALLOC( new = malloc (sizeof (struct fd_list)) ); + + fd_list_init(new, *item); + *item = NULL; + + /* lock the queue */ + CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); + + /* Add the new item at the end */ + fd_list_insert_before( &queue->list, new); + queue->count++; + if (queue->high && ((queue->count % queue->high) == 0)) { + call_cb = 1; + queue->highest = queue->count; + } + + /* Signal if threads are asleep */ + if (queue->thrs > 0) { + CHECK_POSIX( pthread_cond_signal(&queue->cond) ); + } + + /* Unlock */ + CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); + + /* Call high-watermark cb as needed */ + if (call_cb && queue->h_cb) + (*queue->h_cb)(queue, &queue->data); + + /* Done */ + return 0; +} + +/* Pop the first item from the queue */ +static void * mq_pop(struct fifo * queue) +{ + void * ret = NULL; + struct fd_list * li; + + ASSERT( ! FD_IS_LIST_EMPTY(&queue->list) ); + + fd_list_unlink(li = queue->list.next); + queue->count--; + ret = li->o; + free(li); + + return ret; +} + +/* Check if the low watermark callback must be called. */ +static __inline__ int test_l_cb(struct fifo * queue) +{ + if ((queue->high == 0) || (queue->low == 0) || (queue->l_cb == 0)) + return 0; + + if (((queue->count % queue->high) == queue->low) && (queue->highest > queue->count)) { + queue->highest -= queue->high; + return 1; + } + + return 0; +} + +/* Try poping an item */ +int fd_fifo_tryget_int ( struct fifo * queue, void ** item ) +{ + int wouldblock = 0; + int call_cb = 0; + + TRACE_ENTRY( "%p %p", queue, item ); + + /* Check the parameters */ + CHECK_PARAMS( CHECK_FIFO( queue ) && item ); + + /* lock the queue */ + CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); + + /* Check queue status */ + if (queue->count > 0) { + /* There are elements in the queue, so pick the first one */ + *item = mq_pop(queue); + call_cb = test_l_cb(queue); + } else { + wouldblock = 1; + *item = NULL; + } + + /* Unlock */ + CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); + + /* Call low watermark callback as needed */ + if (call_cb) + (*queue->l_cb)(queue, &queue->data); + + /* Done */ + return wouldblock ? EWOULDBLOCK : 0; +} + +/* This handler is called when a thread is blocked on a queue, and cancelled */ +static void fifo_cleanup(void * queue) +{ + struct fifo * q = (struct fifo *)queue; + TRACE_ENTRY( "%p", queue ); + + /* Check the parameter */ + if ( ! CHECK_FIFO( q )) { + TRACE_DEBUG(INFO, "Invalid queue, skipping handler"); + return; + } + + /* The thread has been cancelled, therefore it does not wait on the queue anymore */ + q->thrs--; + + /* Now unlock the queue, and we're done */ + CHECK_POSIX_DO( pthread_mutex_unlock( &q->mtx ), /* nothing */ ); + + /* End of cleanup handler */ + return; +} + +/* The internal function for fd_fifo_timedget and fd_fifo_get */ +static int fifo_tget ( struct fifo * queue, void ** item, int istimed, const struct timespec *abstime) +{ + int timedout = 0; + int call_cb = 0; + + /* Check the parameters */ + CHECK_PARAMS( CHECK_FIFO( queue ) && item && (abstime || !istimed) ); + + /* Initialize the return value */ + *item = NULL; + + /* lock the queue */ + CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); + +awaken: + /* Check queue status */ + if (queue->count > 0) { + /* There are items in the queue, so pick the first one */ + *item = mq_pop(queue); + call_cb = test_l_cb(queue); + } else { + int ret = 0; + /* We have to wait for a new item */ + queue->thrs++ ; + pthread_cleanup_push( fifo_cleanup, queue); + if (istimed) { + ret = pthread_cond_timedwait( &queue->cond, &queue->mtx, abstime ); + } else { + ret = pthread_cond_wait( &queue->cond, &queue->mtx ); + } + pthread_cleanup_pop(0); + queue->thrs-- ; + if (ret == 0) + goto awaken; /* test for spurious wake-ups */ + + if (istimed && (ret == ETIMEDOUT)) { + timedout = 1; + } else { + /* Unexpected error condition (means we need to debug) */ + ASSERT( ret == 0 /* never true */ ); + } + } + + /* Unlock */ + CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); + + /* Call low watermark callback as needed */ + if (call_cb) + (*queue->l_cb)(queue, &queue->data); + + /* Done */ + return timedout ? ETIMEDOUT : 0; +} + +/* Get the next available item, block until there is one */ +int fd_fifo_get_int ( struct fifo * queue, void ** item ) +{ + TRACE_ENTRY( "%p %p", queue, item ); + return fifo_tget(queue, item, 0, NULL); +} + +/* Get the next available item, block until there is one, or the timeout expires */ +int fd_fifo_timedget_int ( struct fifo * queue, void ** item, const struct timespec *abstime ) +{ + TRACE_ENTRY( "%p %p %p", queue, item, abstime ); + return fifo_tget(queue, item, 1, abstime); +} +