ocs init
This commit is contained in:
10
plat/diameter/daemon/daemon.c
Normal file
10
plat/diameter/daemon/daemon.c
Normal file
@@ -0,0 +1,10 @@
|
||||
extern int fd_main(int argc, char * argv[]);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
|
||||
fd_main(argc, argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
19
plat/diameter/doc/acl_wl.conf.sample
Normal file
19
plat/diameter/doc/acl_wl.conf.sample
Normal file
@@ -0,0 +1,19 @@
|
||||
# Configuration file for the peer whitelist extension.
|
||||
#
|
||||
# This extension is meant to allow connection from remote peers, without actively
|
||||
# maintaining this connection ourselves (as it would be the case by declaring the
|
||||
# peer in a ConnectPeer directive).
|
||||
# The format of this file is very simple. It contains a list of peer names
|
||||
# separated by spaces or newlines.
|
||||
#
|
||||
# The peer name must be a fqdn. We allow also a special "*" character as the
|
||||
# first label of the fqdn, to allow all fqdn with the same domain name.
|
||||
# Example: *.example.net will allow host1.example.net and host2.example.net
|
||||
#
|
||||
# At the beginning of a line, the following flags are allowed (case sensitive) -- either or both can appear:
|
||||
# ALLOW_OLD_TLS : we accept unprotected CER/CEA exchange with Inband-Security-Id = TLS
|
||||
# ALLOW_IPSEC : we accept implicitly protected connection with with peer (Inband-Security-Id = IPSec)
|
||||
# It is specified for example as:
|
||||
# ALLOW_IPSEC vpn.example.net vpn2.example.net *.vpn.example.net
|
||||
# These flag take effect from their position, until the end of the line.
|
||||
|
||||
82
plat/diameter/doc/app_acct.conf.sample
Normal file
82
plat/diameter/doc/app_acct.conf.sample
Normal file
@@ -0,0 +1,82 @@
|
||||
#######################
|
||||
# This file contains the description of configuration and general information about the
|
||||
# "App_Acct" extension.
|
||||
|
||||
# This extension provides a simple Diameter Accounting server.
|
||||
# The extension does receive the Accounting-Request message, then
|
||||
# saves the contents of the AVP in a database, as configured here.
|
||||
# The data is not processed at all. The intent is that a dedicated
|
||||
# application will then pull from this database and process the data (consolidate
|
||||
# sessions, ...)
|
||||
|
||||
# In order to enable this extension, the main freeDiameter configuration file
|
||||
# must contain the following declaration:
|
||||
# LoadExtension = "extensions/app_acct.fdx" : "/path/to/app_acct.conf" ;
|
||||
#######################
|
||||
|
||||
#################
|
||||
## Part I: AVP ##
|
||||
#################
|
||||
|
||||
# Configure here the AVPs that must be stored in the database.
|
||||
# The format is:
|
||||
# "AVP-dictionary-name" = {
|
||||
# field = "db-field-name";
|
||||
# required;
|
||||
# multi=N;
|
||||
# };
|
||||
# Where:
|
||||
# AVP-dictionary-name:
|
||||
# The name of the AVP, such as "Session-Id". Only this field is mandatory.
|
||||
# field="...":
|
||||
# The name of the field in the database where is AVP contents will be saved.
|
||||
# The default is that the field is named as the AVP-dictionary-name.
|
||||
# required:
|
||||
# By default, if the AVP is not in the Diameter message, it is not passed in
|
||||
# the INSERT statement (will get NULL). If Required is specified for the AVP,
|
||||
# an error is returned in the Diameter answer, and the data is discarded.
|
||||
# multi=N:
|
||||
# If an AVP may appear several times in a request, you may specify a number of
|
||||
# occurrences to save in the database. The Nth first occurrences of the AVP
|
||||
# will be saved in fields "db-field-name1", "db-field-name2", ... "db-field-nameN"
|
||||
#
|
||||
# In case the default behavior for an AVP is fine, you can use the short syntax:
|
||||
# "AVP-dictionary-name";
|
||||
#
|
||||
# Note that at the moment, GROUPED AVP are not supported. Also, only the top-level AVPs are
|
||||
# searched. This behavior can be changed quite easily if needed.
|
||||
|
||||
# You may look at contrib/app_acct_tools/app_acct.conf and database.sql files
|
||||
# for an example of setup.
|
||||
|
||||
|
||||
#######################
|
||||
## Part II: Database ##
|
||||
#######################
|
||||
|
||||
# You must specify the connection information to the database here.
|
||||
# Please note that if the connection is terminated, it will trig the shutdown of the freeDiameter daemon
|
||||
# For this reason, you should as much as possible use a local database.
|
||||
|
||||
# ConnInfo:
|
||||
# The connection string to the database. See http://www.postgresql.org/docs/8.4/static/libpq-connect.html
|
||||
# Example: ConnInfo = "host=localhost port=5432 dbname=acct user=acct password=freediameter";
|
||||
|
||||
# Table:
|
||||
# The name of the table to use. The fields and types in this table must be created accordingly to the Part I configuration in this file.
|
||||
# Example: Table = "incoming";
|
||||
|
||||
# Timestamp_field:
|
||||
# Optionally, you can specify a name of a field that will receive the value 'now' when a new record is inserted.
|
||||
# Default: no timestamp is inserted.
|
||||
# Example: Timestamp_field = "recorded_on";
|
||||
|
||||
# Server_name_field:
|
||||
# Optionally, you can specify a field which will receive the Diameter Identity of the local server for each record saved.
|
||||
# This is useful especially if you have several Accounting servers and want to check Load-Balancing behavior or so,
|
||||
# after aggregating all the data.
|
||||
# Default: no server name inserted.
|
||||
# Example: Server_name_field = "recorded_serv";
|
||||
|
||||
|
||||
|
||||
44
plat/diameter/doc/app_diameap.conf.sample
Normal file
44
plat/diameter/doc/app_diameap.conf.sample
Normal file
@@ -0,0 +1,44 @@
|
||||
##### a sample Configuration file for DiamEAP
|
||||
|
||||
# MySQL Database settings
|
||||
# Specify connection parameters for DiamEAP MySQL database:
|
||||
# - username and password to connect to the MySQL Server
|
||||
# - databaseserver : the MySQL server location. It can be the IP address or the host name where MySQL server is located. 'localhost' can be used as the location if the server is locatd in the same host than DiamEAP.
|
||||
# - database_name : the created database for DiamEAP.
|
||||
|
||||
# Syntax :
|
||||
# DiamEAP_MySQL = "<username>" , "<password>" , "<databaseserver>" , "<database_name>";
|
||||
|
||||
|
||||
|
||||
##### Extensible Authentication Protocol (EAP) Methods Plugins #####
|
||||
# An EAP method is identified by its EAP method name, EAP TYPE, VENDOR and path to its EAP Method Plugin.
|
||||
# Optionally, path to a configuration file of plugin can also be provided.
|
||||
# Location of plugins and their configuration files can be provided by the absolute pathor the relative path from the location configured in cmake.
|
||||
# An EAP Method Plugin can not be loaded twice. Only the first added method will be loaded.
|
||||
# Any EAP Method plugin with a same EAP_TYPE value than an already loaded one will be discarded.
|
||||
# EAP Methods are added in the same order they are added to the the configuration file.
|
||||
|
||||
# Syntax :
|
||||
# Load_plugin = "<EAP method name>":EAP_TYPE:VENDOR:"<Path to EAP method >":"<Path to configuration file>";
|
||||
#
|
||||
# Example:
|
||||
# Load_plugin = "EAP MD5":4:0:"/extensions/eap_md5.emp":"";
|
||||
# Load_plugin = "EAP TLS":13:0;"/extensions/eap_tls.emp":"/doc/eap_tls_plugin.diameap.conf";
|
||||
|
||||
Load_plugin = "EAP Identity":1:0:"/extensions/eap_identity.emp":"";
|
||||
|
||||
# Enable/disable checking User's Identity. If disabled, default parameters value will be used for authentication and authorization attributes.
|
||||
# Default values are defined in database for 'Default User'.
|
||||
Check_User_Identity = 1;
|
||||
|
||||
# In addition to authentication DiamEAP can be configured to check authorization of authenticated users. If set to 0 authorization is disabled, otherwise enabled.( by default disabled).
|
||||
Authorization = 1;
|
||||
|
||||
# This parameter specify the maximum number of seconds provided to the access device for responding to an EAP request. (by default set to 30 seconds)
|
||||
#Multi_Round_Time_Out=30;
|
||||
|
||||
# After receivin a number of invalid EAP packets, DiamEAP reject the authentication by responding with Failure Authentication.
|
||||
# The default value of maximum number of invalid EAP packets is set to 5 packets.
|
||||
# The value of maximum invalid EAP packets can be modified by adding a new value.
|
||||
#MAX_Invalid_EAP_Packets=5;
|
||||
105
plat/diameter/doc/app_radgw.conf.sample
Normal file
105
plat/diameter/doc/app_radgw.conf.sample
Normal file
@@ -0,0 +1,105 @@
|
||||
# This file contains information for configuring the app_radgw extension.
|
||||
# To find how to have freeDiameter load this extension, please refer to the freeDiameter documentation.
|
||||
#
|
||||
# The app_radgw extension allows a freeDiameter agent to serve as a
|
||||
# RADIUS/Diameter gateway. Typically, a RADIUS client (e.g. a NAS) will connect to
|
||||
# this agent, and the message will be converted to Diameter and sent to a Diameter server.
|
||||
#
|
||||
# Note that this extension does not provide a fully functionnal RADIUS/Diameter gateway.
|
||||
# You need to load plugins to handle specific RADIUS messages and convert them to
|
||||
# Diameter apps such as NASREQ, EAP, ... See the next section for information.
|
||||
|
||||
|
||||
###########
|
||||
# PLUGINS #
|
||||
###########
|
||||
|
||||
# Additional plugins must be loaded to support specific RADIUS messages and attributes.
|
||||
|
||||
# Plugins are registered either for every message, or by port (auth or acct), or by port and code.
|
||||
# The general format is:
|
||||
# RGWX = plugin [: conf_file] [: port] [: code(s)] ;
|
||||
# Where:
|
||||
# plugin is the quoted file name (relative or absolute) of the plugin to load (.rgwx files).
|
||||
# conf_file (optional) is the quoted name of the configuration file.
|
||||
# port (optional), either auth or acct.
|
||||
# If not specified, extension is called for messages incoming on both ports
|
||||
# code(s): space-separated list of command codes for which this extension must be called.
|
||||
# If not specified, the extension is called for all incoming messages.
|
||||
# The values are interpreted as hexadecimal.
|
||||
#
|
||||
# The plugins are called in the order they appear in this file.
|
||||
# Here are some explained examples:
|
||||
# RGWX = "3579.rgwx"; Load this extension and call it for all messages. No configuration file.
|
||||
# RGWX = "3579.rgwx" : "3579.conf"; Same as previous but with a configuration file specified.
|
||||
# RGWX = "3579.rgwx" : auth; No configuration file, but called only for RADIUS messages received on authentication port.
|
||||
# RGWX = "3579.rgwx" : 4 8 b; Called for messages with command code 4, 8, or 11 only.
|
||||
# RGWX = "3579.rgwx" : "3579.conf" : auth : 4 8 b; All parameters combined.
|
||||
|
||||
# Once the list of extensions for an incoming message has been called (or if the list is empty),
|
||||
# an error is logged if some RADIUS attributes of the message have not been handled.
|
||||
|
||||
RGWX = "extensions/echodrop.rgwx" : "echodrop.rgwx.conf"; # See echodrop.rgwx.conf.sample file
|
||||
RGWX = "extensions/auth.rgwx" : auth;
|
||||
RGWX = "extensions/acct.rgwx" : acct;
|
||||
# RGWX = "extensions/debug.rgwx"; # Uncomment to see the result of the translation plugins.
|
||||
|
||||
# For some extensions (auth, acct), a false configuration file name
|
||||
# can be passed to specify flags, such as "nonai" to ignore NAI-based routing.
|
||||
|
||||
##################
|
||||
# RADIUS Clients #
|
||||
##################
|
||||
|
||||
# Each RADIUS client must be declared in the form:
|
||||
# nas = IP / shared-secret ;
|
||||
# IP can be ipv4 or ipv6
|
||||
# port can be additionaly restricted with brackets: IP[port] (ex: 192.168.0.1[1812])
|
||||
# shared-secret can be a quoted string, or a list of hexadecimal values.
|
||||
# examples:
|
||||
# nas = 192.168.100.1 / "secret key" ; # the shared secret buffer is 0x736563726574206b6579 (length 10 bytes)
|
||||
# nas = fe00::1 / 73 65 63 72 65 74 20 6b 65 79; # same shared secret as previously
|
||||
# When a packet is received from an IP not declared here, it is discarded.
|
||||
|
||||
# If the RADIUS client is a Proxy that forwards messages from different peers, it must be
|
||||
# declared instead as follow:
|
||||
# pxy = IP / shared-secret ;
|
||||
# Note that it is not recommended to use this gateway implementation with a proxy currently,
|
||||
# since the management of duplicate messages might be insufficient.
|
||||
|
||||
# The old notation cli = ... is equivalent to nas = ... and kept for backward compatibility.
|
||||
|
||||
|
||||
####################
|
||||
# Authentication #
|
||||
# Authorization #
|
||||
####################
|
||||
|
||||
# Enable the RADIUS/Diameter authentication/authorization gateway?
|
||||
# auth_server_enable = 1;
|
||||
|
||||
# The port on which the accounting server listens
|
||||
# auth_server_port = 1812;
|
||||
|
||||
# The IPv4 on which to bind the server, or "disable" if IPv4 must not be used.
|
||||
# auth_server_ip4 = 0.0.0.0;
|
||||
|
||||
# The IPv6 address to which the server is bound, or "disable"
|
||||
# auth_server_ip6 = :: ;
|
||||
|
||||
|
||||
################
|
||||
# Accounting #
|
||||
################
|
||||
|
||||
# Enable the RADIUS/Diameter accounting gateway?
|
||||
# acct_server_enable = 1;
|
||||
|
||||
# The port on which the accounting server listens
|
||||
# acct_server_port = 1813;
|
||||
|
||||
# The IPv4 on which to bind the server, or "disable" if no IPv4 is wanted.
|
||||
# acct_server_ip4 = 0.0.0.0;
|
||||
|
||||
# The IPv6 address to which the server is bound, or "disable"
|
||||
# acct_server_ip6 = :: ;
|
||||
97
plat/diameter/doc/app_redirect.conf.sample
Normal file
97
plat/diameter/doc/app_redirect.conf.sample
Normal file
@@ -0,0 +1,97 @@
|
||||
# This file contains the configuration for the app_redirect extension of freeDiameter.
|
||||
#
|
||||
# This extension provides configurable Redirect messages.
|
||||
|
||||
# Lines starting with a # are comments and ignored.
|
||||
# Spaces and newlines are not meaningful, except inside quoted areas.
|
||||
|
||||
#########################################################################################
|
||||
# See Diameter RFC for a detailed explanation on Redirects semantics #
|
||||
#########################################################################################
|
||||
|
||||
## default_redirect_cache_time
|
||||
# Specify the default value for Redirect-Max-Cache-Time.
|
||||
# This value can be overwritten for each rule as specified below.
|
||||
# If this value is not specified, the default is:
|
||||
#default_redirect_cache_time = 86400; ## => 1 day
|
||||
|
||||
# The remaining of this file contains a list of RULE elements.
|
||||
# Each RULE consists in three parts:
|
||||
# - a CRITERIA that specifies which messages the RULE applies to.
|
||||
# - a REDIRECT_TYPE that specifies what type of redirect is to be sent, and its duration.
|
||||
# - a TARGET_HOSTS list that specifies the host(s) to send the message to.
|
||||
#
|
||||
# The rules are matched in the order they appear in this file. Once a rule has matched, the
|
||||
# remaining rules are not processed.
|
||||
#
|
||||
# The basic format of a rule is:
|
||||
# REDIRECT_TYPE : CRITERIA to TARGET_HOSTS ;
|
||||
|
||||
# These are a few examples. The definition of each term follows.
|
||||
#
|
||||
# 1) REALM_AND_APPLICATION : app=3 "Destination-Realm"="myrealm.net" to "aaas://acct1.myrealm.net" "aaas://acct2.myrealm.net";
|
||||
# will ask all peers sending a Base Accounting message for realm "myrealm.net" to send
|
||||
# this message directly to either 'acct1.myrealm.net' or 'acct2.myrealm.net'.
|
||||
#
|
||||
# 2) ALL_SESSION 3600 : "Origin-AAA-Protocol"=1 "Destination-Realm"="myrealm.net" to "aaas://raddiam.myrealm.net";
|
||||
# Will ask any peer sending messages translated from RADIUS and targeted to this realm
|
||||
# to address all the messages from the same session to 'raddiam.myrealm.net'. The
|
||||
# redirect entry should be stored for 1 hour.
|
||||
#
|
||||
# 3) ALL_HOST : from.realm=[".*\.(fr|de|es)"] to "aaas://relay-EU.myrealm.net";
|
||||
# ALL_HOST : from.realm=[".*\.(cn|jp|vn)"] to "aaas://relay-ASIA.myrealm.net";
|
||||
# Redirect messages to different relays depending on where they come from.
|
||||
#
|
||||
# 4) ALL_HOST : to "aaas://newserv.myrealm.net";
|
||||
# This server was relocated, tell all peers to go directly to the new one.
|
||||
# This rule should appear last because it matches all messages, so further rules will never be used.
|
||||
|
||||
|
||||
#
|
||||
# REDIRECT_TYPE
|
||||
#
|
||||
|
||||
# The redirect_type is one of the following (see Redirect-Host-Usage AVP definition in RFC for semantics):
|
||||
# DONT_CACHE
|
||||
# ALL_SESSION
|
||||
# ALL_REALM
|
||||
# REALM_AND_APPLICATION
|
||||
# ALL_APPLICATION
|
||||
# ALL_HOST
|
||||
# ALL_USER
|
||||
|
||||
# In addition, an integer can follow. If specified, it overwrites the default_redirect_cache_time
|
||||
# value for this rule. The value is always specified in seconds.
|
||||
|
||||
#
|
||||
# CRITERIA
|
||||
#
|
||||
|
||||
# Each RULE can contain 0 or more criteria.
|
||||
# If no criteria is specified, all messages are assumed to match (wildcard).
|
||||
# If more than one criteria is specified, an "AND" relationship is assumed.
|
||||
# If you need to specify "OR", just create separate rules.
|
||||
#
|
||||
# In the following definitions, "STR/REG" stands for:
|
||||
# - a quoted string "some.peer" that will match exactly this string (case-insensitive), or
|
||||
# - a bracket-quoted string ["some regex"] that will be interpreted as a POSIX extended regular expression (case-sensitive), and attempt to match the string.
|
||||
#
|
||||
# A criteria is one of the following:
|
||||
# from.id="STR/REG" -> matches messages received from peer with this Diameter Identity.
|
||||
# from.realm="STR/REG" -> matches messages received from peer with this Realm.
|
||||
# app=U32_VALUE -> matches messages with this Diameter Application-Id value in its header.
|
||||
# "AVP-name"=U32_VALUE -> matches messages that contain an avp "AVP-name" (replace with the realm name) with this value.
|
||||
# "AVP-name"="STR/REG" -> matches messages that contain an avp "AVP-name" (replace with the realm name) with this .
|
||||
|
||||
#
|
||||
# TARGET_HOSTS
|
||||
#
|
||||
|
||||
# This is a simple list of DiameterURI that must be sent back.
|
||||
# See the RFC for valid format of Diameter URI:
|
||||
# "aaa://" FQDN [ port ] [ transport ] [ protocol ]
|
||||
# "aaas://" FQDN [ port ] [ transport ] [ protocol ]
|
||||
|
||||
######################################################################################
|
||||
|
||||
|
||||
28
plat/diameter/doc/app_sip.conf.sample
Normal file
28
plat/diameter/doc/app_sip.conf.sample
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
# MODE Diameter-SIP server (DSSERVER) or Subscriber Locator (SL)
|
||||
#You must have at least in your network a Diameter SIP server and a Subscriber Locator (on different nodes)
|
||||
mode = DSSERVER;
|
||||
|
||||
|
||||
# Administrator commands port (port should be provided with "-p" in remote line)
|
||||
ppr_port=90;
|
||||
rtr_port=91;
|
||||
|
||||
|
||||
#******************#
|
||||
#*****DATABASE*****#
|
||||
#******************#
|
||||
# DATASOURCE: MYSQL
|
||||
datasource = MYSQL;
|
||||
|
||||
#MYSQL connection details
|
||||
mysql_login = "login";
|
||||
mysql_password = "password";
|
||||
mysql_database = "db";
|
||||
mysql_server = "server.fr";
|
||||
|
||||
#If value=0, default port for mysql will be set
|
||||
mysql_port = 0;
|
||||
|
||||
#Prefix for tables (default is "ds")
|
||||
mysql_prefix = "ds";
|
||||
117
plat/diameter/doc/app_sip.sql
Normal file
117
plat/diameter/doc/app_sip.sql
Normal file
@@ -0,0 +1,117 @@
|
||||
--Can be used in phpMyAdmin
|
||||
|
||||
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
|
||||
|
||||
--
|
||||
-- DIAMETER SERVER DATABASE
|
||||
--
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `ds_data_types`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `ds_data_types` (
|
||||
`id_data_type` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`label_type` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id_data_type`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `ds_networks`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `ds_networks` (
|
||||
`id_network` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`label_network` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id_network`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `ds_sip_aor`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `ds_sip_aor` (
|
||||
`id_sip_aor` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`id_user` int(11) NOT NULL,
|
||||
`sip_aor` varchar(255) NOT NULL,
|
||||
`sip_server_uri` varchar(255) DEFAULT NULL,
|
||||
`registered` tinyint(1) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id_sip_aor`,`id_user`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `ds_sip_services`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `ds_sip_services` (
|
||||
`id_service` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`label_service` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id_service`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `ds_users`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `ds_users` (
|
||||
`id_user` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(50) NOT NULL,
|
||||
`password` varchar(50) NOT NULL,
|
||||
`SIP_Server_URI` varchar(255) DEFAULT NULL,
|
||||
`temp_SIP_Server_URI` varchar(255) DEFAULT NULL,
|
||||
`authentication_pending` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`registrated` tinyint(1) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id_user`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `ds_user_data`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `ds_user_data` (
|
||||
`id_user_data` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`id_sip_aor` int(11) NOT NULL,
|
||||
`id_data_type` int(11) NOT NULL,
|
||||
`data` longblob NOT NULL,
|
||||
PRIMARY KEY (`id_user_data`,`id_sip_aor`,`id_data_type`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `ds_user_networks`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `ds_user_networks` (
|
||||
`id_user_network` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`id_user` int(11) NOT NULL,
|
||||
`id_network` int(11) NOT NULL,
|
||||
PRIMARY KEY (`id_user_network`,`id_user`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `ds_user_services`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `ds_user_services` (
|
||||
`id_user_service` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`id_user` int(11) NOT NULL,
|
||||
`id_service` int(11) NOT NULL,
|
||||
`compulsory` tinyint(1) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id_user_service`,`id_user`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
|
||||
|
||||
21
plat/diameter/doc/app_sip_SL.sql
Normal file
21
plat/diameter/doc/app_sip_SL.sql
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
|
||||
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
|
||||
|
||||
--
|
||||
-- SUBSCRIBER LOCATOR DATABASE
|
||||
--
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `ds_sip_aor_map`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `ds_sip_aor_map` (
|
||||
`id_map` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`sip_aor` varchar(255) NOT NULL,
|
||||
`diameter_uri` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id_map`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
|
||||
|
||||
783
plat/diameter/doc/dbg_interactive.py.sample
Normal file
783
plat/diameter/doc/dbg_interactive.py.sample
Normal file
@@ -0,0 +1,783 @@
|
||||
# Example file for the dbg_interactive.fdx extension.
|
||||
#
|
||||
# This extension provides an interactive python interpreter console that allows
|
||||
# interacting with freeDiameter framework.
|
||||
#
|
||||
# The adaptation layer between Python and C is provided by SWIG (http://swig.org).
|
||||
# You may refer to SWIG documentation for more information on how the wrapper is generated and used.
|
||||
# The name of the module wrapping freeDiameter framework is: _fDpy
|
||||
#
|
||||
# Similar to all freeDiameter extensions, an optional filename can be specified in the
|
||||
# main freeDiameter.conf configuration file for the dbg_interactive.fdx extension.
|
||||
# If such file is provided, it will be passed to the python interpreter as a python script
|
||||
# to execute. Otherwise, the interpreter will be interactive.
|
||||
#
|
||||
# SWIG deals with structures as follow:
|
||||
# Given the structure:
|
||||
# struct foo { int a; }
|
||||
# The following functions are available to python (their C equivalent processing is given in [ ]):
|
||||
# s = new_foo() [ s = calloc(1, sizeof(struct foo)) ]
|
||||
# foo_a_set(s, 2) [ s->a = 2 ]
|
||||
# foo_a_get(s) [ returns s->a value ]
|
||||
# delete_foo(s) [ free(s) ]
|
||||
#
|
||||
# In addition, thanks to the proxy (aka shadow) class, we can also do the more user-friendly:
|
||||
# s = foo()
|
||||
# s.a = 2
|
||||
# s.a
|
||||
# del s
|
||||
#
|
||||
|
||||
# The remaining of this file gives some examples of how to use the python interpreter.
|
||||
# Note that at the moment not 100% of the framework is usable.
|
||||
# You may have to extend some classes or write some typemaps in the source code
|
||||
# of the extension to do what you want.
|
||||
|
||||
|
||||
############# Compilation-time constants (from freeDiameter-host.h) ############
|
||||
|
||||
# Display current version
|
||||
print "%s %d.%d.%d" % (FD_PROJECT_NAME, FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR, FD_PROJECT_VERSION_REV)
|
||||
|
||||
|
||||
############# Debug ############
|
||||
|
||||
# Change the global debug level of the framework (cvar contains all global variables)
|
||||
cvar.fd_g_debug_lvl = 1
|
||||
|
||||
|
||||
# Turn on debug for a specific function (if framework compiled with DEBUG support)
|
||||
cvar.fd_debug_one_function = "gc_th_fct"
|
||||
|
||||
|
||||
# Print messages to freeDiameter's debug facility
|
||||
# Note: the python version does not support printf-like argument list. The formating should be done in python.
|
||||
# See SWIG documentation about varargs functions for more information.
|
||||
fd_log(FD_LOG_NOTICE, "3 + 4 = %d" % (7))
|
||||
|
||||
|
||||
# Display some framework state information
|
||||
conf = fd_conf_dump();
|
||||
print conf;
|
||||
|
||||
fd_peer_dump_list(0)
|
||||
fd_servers_dump(0)
|
||||
fd_ext_dump(0)
|
||||
|
||||
|
||||
############# Global variables ############
|
||||
|
||||
# Display the local Diameter Identity:
|
||||
print "Local Diameter Identity:", cvar.fd_g_config.cnf_diamid
|
||||
|
||||
# Display realm, using the low-level functions (skip proxy classe definitions):
|
||||
print "Realm:", _fDpy.fd_config_cnf_diamrlm_get(_fDpy.cvar.fd_g_config)
|
||||
|
||||
|
||||
|
||||
############# Lists ############
|
||||
|
||||
# Note: we use different names from the C API here, for usability.
|
||||
l1 = fd_list() # Will be our sentinel
|
||||
l2 = fd_list()
|
||||
l3 = fd_list()
|
||||
l1.isempty()
|
||||
l1.insert_next(l2) # l1 -> l2
|
||||
l1.isempty()
|
||||
l1.insert_prev(l3) # l1 -> l2 -> l3 (circular list)
|
||||
l1.dump()
|
||||
l3.detach() # l1 -> l2
|
||||
l4=fd_list()
|
||||
l5=fd_list()
|
||||
l3.insert_next(l4) # l3 -> l4
|
||||
l3.insert_next(l5) # l3 -> l5 -> l4
|
||||
l1.concat(l3) # l1 -> l2 -> l5 -> l4
|
||||
|
||||
elements = l1.enum_as() # default: enumerates as fd_list. Warning: this a copy, changing the python list has no effect on the underlying fd_list.
|
||||
for li in elements:
|
||||
li.dump()
|
||||
|
||||
del elements
|
||||
del l2
|
||||
del l3
|
||||
del l4
|
||||
del l5
|
||||
l1.isempty() # The destructor has an implicit fd_list_unlink call
|
||||
del l1
|
||||
|
||||
|
||||
############# Hash ############
|
||||
|
||||
hex(fd_os_hash("hello world")) # It accepts binary data
|
||||
|
||||
|
||||
############# Dictionary ############
|
||||
|
||||
##### Create a dedicated dictionary for our tests
|
||||
d = dictionary()
|
||||
d.dump()
|
||||
|
||||
# New vendor
|
||||
v = dict_vendor_data()
|
||||
v.vendor_id = 123
|
||||
v.vendor_name = "My test vendor"
|
||||
my_vendor = d.new_obj(DICT_VENDOR, v)
|
||||
del v
|
||||
d.dump()
|
||||
d.vendors_list()
|
||||
|
||||
# Compact invocation also possible:
|
||||
v2 = dict_vendor_data(124, "My test vendor 2")
|
||||
del v2
|
||||
|
||||
# New application
|
||||
a = dict_application_data()
|
||||
a.application_id = 99
|
||||
a.application_name = "My test appl"
|
||||
my_appl = d.new_obj(DICT_APPLICATION, a, my_vendor)
|
||||
del a
|
||||
|
||||
a2 = dict_application_data(99, "My test appl 2")
|
||||
del a2
|
||||
|
||||
# New type (callbacks are not supported yet...)
|
||||
t = dict_type_data()
|
||||
t.type_base = AVP_TYPE_INTEGER32
|
||||
t.type_name = "My integer AVP"
|
||||
my_type_int = d.new_obj(DICT_TYPE, t, my_appl)
|
||||
t.type_base = AVP_TYPE_OCTETSTRING
|
||||
t.type_name = "My binary buffer AVP"
|
||||
my_type_os = d.new_obj(DICT_TYPE, t, my_appl)
|
||||
del t
|
||||
|
||||
t2 = dict_type_data(AVP_TYPE_UNSIGNED32, "u32 type")
|
||||
del t2
|
||||
|
||||
# Constants
|
||||
c = dict_enumval_data()
|
||||
c.enum_name = "AVP_VALUE_TROIS"
|
||||
c.enum_value.i32 = 3
|
||||
d.new_obj(DICT_ENUMVAL, c, my_type_int)
|
||||
|
||||
c.enum_name = "A_BUFFER_CONSTANT"
|
||||
c.enum_value.os = "This is a very long AVP value that we prefer to represent as a constant"
|
||||
c.enum_value.os.dump()
|
||||
d.new_obj(DICT_ENUMVAL, c, my_type_os)
|
||||
del c
|
||||
|
||||
c2 = dict_enumval_data("enum 23", 23) # The constructor only accepts unsigned32, for other values, set them afterwards
|
||||
c3 = dict_enumval_data("enum other")
|
||||
c3.os = "other value"
|
||||
del c2
|
||||
del c3
|
||||
|
||||
# AVP
|
||||
a = dict_avp_data()
|
||||
a.avp_code = 234
|
||||
a.avp_name = "my integer avp"
|
||||
a.avp_flag_mask = AVP_FLAG_MANDATORY
|
||||
a.avp_basetype = AVP_TYPE_INTEGER32
|
||||
my_avp_int = d.new_obj(DICT_AVP, a, my_type_int)
|
||||
|
||||
a.avp_vendor = 123
|
||||
a.avp_name = "my OS avp"
|
||||
a.avp_flag_mask = AVP_FLAG_MANDATORY + AVP_FLAG_VENDOR
|
||||
a.avp_flag_val = AVP_FLAG_VENDOR
|
||||
a.avp_basetype = AVP_TYPE_OCTETSTRING
|
||||
my_avp_os = d.new_obj(DICT_AVP, a, my_type_os)
|
||||
del a
|
||||
|
||||
a2 = dict_avp_data(235, "no vendor, not mandatory", AVP_TYPE_OCTETSTRING)
|
||||
a3 = dict_avp_data(236, "vendor 12, not mandatory", AVP_TYPE_OCTETSTRING, 12)
|
||||
a4 = dict_avp_data(237, "vendor 12, mandatory", AVP_TYPE_OCTETSTRING, 12, 1)
|
||||
a5 = dict_avp_data(238, "no vendor, mandatory", AVP_TYPE_OCTETSTRING, 0, 1)
|
||||
del a2
|
||||
del a3
|
||||
del a4
|
||||
del a5
|
||||
|
||||
|
||||
# Command
|
||||
c = dict_cmd_data()
|
||||
c.cmd_code = 345
|
||||
c.cmd_name = "My-Python-Request"
|
||||
c.cmd_flag_mask = CMD_FLAG_REQUEST + CMD_FLAG_PROXIABLE
|
||||
c.cmd_flag_val = CMD_FLAG_REQUEST + CMD_FLAG_PROXIABLE
|
||||
my_req = d.new_obj(DICT_COMMAND, c, my_appl)
|
||||
c.cmd_name = "My-Python-Answer"
|
||||
c.cmd_flag_val = CMD_FLAG_PROXIABLE
|
||||
my_ans = d.new_obj(DICT_COMMAND, c, my_appl)
|
||||
del c
|
||||
|
||||
c2 = dict_cmd_data(346, "Second-Request", 1) # Default created with PROXIABLE flag.
|
||||
c3 = dict_cmd_data(346, "Second-Answer", 0)
|
||||
del c2
|
||||
del c3
|
||||
|
||||
# Rule
|
||||
r = dict_rule_data()
|
||||
r.rule_avp = my_avp_int
|
||||
r.rule_position = RULE_REQUIRED
|
||||
r.rule_min = -1
|
||||
r.rule_max = -1
|
||||
d.new_obj(DICT_RULE, r, my_req)
|
||||
d.new_obj(DICT_RULE, r, my_ans)
|
||||
r.rule_avp = my_avp_os
|
||||
d.new_obj(DICT_RULE, r, my_req)
|
||||
d.new_obj(DICT_RULE, r, my_ans)
|
||||
del r
|
||||
|
||||
r2 = dict_rule_data(my_avp_int, RULE_REQUIRED) # min & max are optional parameters, default to -1
|
||||
r3 = dict_rule_data(my_avp_int, RULE_REQUIRED, 2, 3) # min is 2, max is 3
|
||||
r4 = dict_rule_data(my_avp_int, RULE_FIXED_HEAD) # The r4.rule_order = 1 by default, change afterwards if needed.
|
||||
del r2
|
||||
del r3
|
||||
del r4
|
||||
|
||||
d.dump()
|
||||
del d
|
||||
|
||||
####### Now play with the "real" dictionary
|
||||
|
||||
gdict = cvar.fd_g_config.cnf_dict
|
||||
|
||||
appl = gdict.search ( DICT_APPLICATION, APPLICATION_BY_ID, 3 )
|
||||
appl.dump()
|
||||
avp = gdict.search ( DICT_AVP, AVP_BY_NAME, "Origin-Host")
|
||||
avp.dump()
|
||||
errcmd = gdict.error_cmd()
|
||||
|
||||
v = avp.getval()
|
||||
print v.avp_code
|
||||
del v
|
||||
|
||||
t = avp.gettype()
|
||||
print t
|
||||
del t
|
||||
|
||||
dict = avp.getdict()
|
||||
del dict
|
||||
|
||||
|
||||
############# Sessions ############
|
||||
|
||||
# handler
|
||||
def my_cleanup(state,sid):
|
||||
print "Cleaning up python state for session:", sid
|
||||
print "Received state:", state
|
||||
del state
|
||||
|
||||
hdl = session_handler(my_cleanup)
|
||||
hdl.dump()
|
||||
del hdl
|
||||
|
||||
# Session
|
||||
hdl = session_handler(my_cleanup)
|
||||
s1 = session()
|
||||
s1.getsid()
|
||||
s2 = session("this.is.a.full.session.id")
|
||||
r,s3,isnew = fd_sess_fromsid("this.is.a.full.session.id") # use this call if "isnew" is really needed...
|
||||
s4 = session("host.id", "optional.part")
|
||||
s4.settimeout(30) # the python wrapper takes a number of seconds as parameter for simplicity
|
||||
s4.dump()
|
||||
|
||||
# states
|
||||
mystate = [ 34, "blah", [ 32, 12 ] ]
|
||||
s1.store(hdl, mystate)
|
||||
del mystate
|
||||
gotstate = s1.retrieve(hdl)
|
||||
print gotstate
|
||||
del gotstate
|
||||
|
||||
|
||||
############# Routing ############
|
||||
|
||||
rd = rt_data()
|
||||
|
||||
rd.add("p1.testbed.aaa", "testbed.aaa")
|
||||
rd.add("p2.testbed.aaa", "testbed.aaa")
|
||||
rd.add("p3.testbed.aaa", "testbed.aaa")
|
||||
rd.add("p4.testbed.aaa", "testbed.aaa")
|
||||
|
||||
rd.remove("p2.testbed.aaa")
|
||||
|
||||
rd.error("p3.testbed.aaa", "relay.testbed.aaa", 3002)
|
||||
|
||||
list = rd.extract(-1)
|
||||
for c in list.enum_as("struct rtd_candidate *"):
|
||||
print "%s (%s): %s" % (c.diamid, c.realm, c.score)
|
||||
|
||||
del rd
|
||||
|
||||
|
||||
# A rt_fwd callback has the following prototype:
|
||||
def my_rtfwd_cb(msg):
|
||||
print "Forwarding the following message:"
|
||||
msg.dump()
|
||||
return [ 0, msg ] # return None instead of msg to stop forwarding.
|
||||
|
||||
fwdhdl = fd_rt_fwd_hdl( my_rtfwd_cb, RT_FWD_REQ )
|
||||
|
||||
|
||||
# A rt_out cb has the following prototype:
|
||||
def my_rtout_cb(msg, list):
|
||||
print "Sending out the following message:"
|
||||
msg.dump()
|
||||
print "The possible candidates are:"
|
||||
for c in list.enum_as("struct rtd_candidate *"):
|
||||
print "%s (%s): %s" % (c.diamid, c.realm, c.score)
|
||||
return 0 # returns an error code (standard errno values)
|
||||
|
||||
outhdl = fd_rt_out_hdl( my_rtout_cb ) # a priority can be specified as 2nd parameter, default is 0.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
############# Messages, AVPs ############
|
||||
|
||||
## AVP
|
||||
|
||||
# Create empty
|
||||
blank_avp = avp()
|
||||
del blank_avp
|
||||
|
||||
# Create from dictionary definitions
|
||||
oh = avp(cvar.fd_g_config.cnf_dict.search ( DICT_AVP, AVP_BY_NAME, "Origin-Host")) # Octet String
|
||||
vi = avp(cvar.fd_g_config.cnf_dict.search ( DICT_AVP, AVP_BY_NAME, "Vendor-Id")) # U32
|
||||
vsai = avp(cvar.fd_g_config.cnf_dict.search ( DICT_AVP, AVP_BY_NAME, "Vendor-Specific-Application-Id")) # Grouped
|
||||
|
||||
# Set values
|
||||
val = avp_value()
|
||||
val.u32 = 123
|
||||
vi.setval(None) # this cleans a previous value (usually not needed)
|
||||
vi.setval(val)
|
||||
val.os = "my.origin.host"
|
||||
oh.setval(val)
|
||||
vsai.add_child(vi) # call as add_child(vi, 1) to add the new AVP at the beginning, default is at the end
|
||||
|
||||
# It is possible to initialize the AVP with a blank value as follow:
|
||||
blank_with_value = avp(None, AVPFL_SET_BLANK_VALUE)
|
||||
# it enables this without doing the setval call:
|
||||
blank_with_value.header().avp_value.u32 = 12
|
||||
|
||||
|
||||
## Messages
|
||||
|
||||
# Create empt (as for avps, pass None or a dictionary object as 1st param, and flags as optional 2nd param)y
|
||||
a_msg = msg()
|
||||
a_msg.dump()
|
||||
del a_msg
|
||||
|
||||
# It is also possible to pass MSGFL_* flags in second parameter (ALLOC_ETEID is default)
|
||||
msg_no_eid = msg(None, 0)
|
||||
msg_no_eid.dump()
|
||||
del msg_no_eid
|
||||
|
||||
# Create from dictionary
|
||||
dwr_dict = cvar.fd_g_config.cnf_dict.search ( DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request" )
|
||||
dwr = msg(dwr_dict)
|
||||
dwr.dump()
|
||||
|
||||
# Create msg from a binary buffer (then you should call parse_dict and parse_rules methods)
|
||||
dwr2 = msg("\x01\x00\x00\x14\x80\x00\x01\x18\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xf0\x00\x01")
|
||||
|
||||
# Create answer from request (optional parameters: dictionary to use, and flags):
|
||||
dwr3 = msg(cvar.fd_g_config.cnf_dict.search ( DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request" ))
|
||||
dwa3 = dwr3.create_answer()
|
||||
dwr3cpy = dwa3.get_query()
|
||||
|
||||
|
||||
## Other functions with AVPs & messages
|
||||
|
||||
# Add the AVPs in the message
|
||||
dwr.add_child(oh)
|
||||
oh.add_next(vsai) # equivalent to add_child on the parent
|
||||
|
||||
# Create a network byte buffer from the message
|
||||
dwr.bufferize()
|
||||
|
||||
# Get first child AVP (fast)
|
||||
avp = dwr.first_child()
|
||||
|
||||
# then:
|
||||
avp = avp.get_next() # when last AVP, returns None
|
||||
|
||||
|
||||
# Get all 1st level children (slower) -- warning, changes to the python list will not be reflected on the underlying message. read-only use.
|
||||
dwr.children()
|
||||
# example use:
|
||||
for a in dwr.children():
|
||||
a.dump(0) # 0 means: dump only this object, do not walk the tree
|
||||
|
||||
|
||||
# Search the first AVP of a given type
|
||||
oh_dict = cvar.fd_g_config.cnf_dict.search( DICT_AVP, AVP_BY_NAME, "Origin-Host")
|
||||
oh = dwr.search( oh_dict )
|
||||
|
||||
# After adding AVPs, the length in the message header is outdated, refresh as follow:
|
||||
dwr.update_length()
|
||||
|
||||
# Get dictionary model for a message or avp
|
||||
dwr.model()
|
||||
oh.model().dump()
|
||||
|
||||
# Retrieve the header of messages & avp:
|
||||
dwr_hdr = dwr.header()
|
||||
dwr_hdr.msg_version
|
||||
dwr_hdr.msg_hbhid
|
||||
|
||||
oh_hdr = oh.header()
|
||||
hex(oh_hdr.avp_flags)
|
||||
oh_hdr.avp_vendor
|
||||
oh_hdr.avp_value.os.as_str()
|
||||
|
||||
|
||||
# Get or set the routing data
|
||||
rd = rt_data()
|
||||
dwr.set_rtd(rd)
|
||||
rd = dwr.get_rtd()
|
||||
|
||||
# Test if message is routable
|
||||
dwr.is_routable()
|
||||
|
||||
# Which peer the message was received from (when received from network)
|
||||
dwr.source()
|
||||
|
||||
# The session corresponding to this message (returns None when no Session-Id AVP is included)
|
||||
dwr.get_session()
|
||||
|
||||
|
||||
# Parse a buffer
|
||||
buf = "\x01\x00\x00@\x80\x00\x01\x18\x00\x00\x00\x00\x00\x00\x00\x00N\x10\x00\x00\x00\x00\x01\x08@\x00\x00\x16my.origin.host\x00\x00\x00\x00\x01\x04@\x00\x00\x14\x00\x00\x01\n@\x00\x00\x0c\x00\x00\x00{"
|
||||
mydwr = msg(buf)
|
||||
# Resolve objects in the dictionary. Return value is None or a struct pei_error in case of problem.
|
||||
mydwr.parse_dict() # if not using the fD global dict, pass it as parameter
|
||||
err = mydwr.parse_rules()
|
||||
err.pei_errcode
|
||||
|
||||
|
||||
# Grouped AVPs are browsed with same methods as messages:
|
||||
gavp = dwr.children()[1]
|
||||
gavp.first_child().dump()
|
||||
gavp.children()
|
||||
|
||||
|
||||
# Send a message:
|
||||
mydwr = msg(buf)
|
||||
mydwr.send()
|
||||
|
||||
# Optionally, a callback can be registered when a request is sent, with an optional object.
|
||||
# This callback takes the answer message as parameter and should return None or a message. (cf. fd_msg_send)
|
||||
def send_callback(msg, obj):
|
||||
print "Received answer:"
|
||||
msg.dump()
|
||||
print "Associated data:"
|
||||
obj
|
||||
return None
|
||||
|
||||
mydwr = msg(buf)
|
||||
mydwr.send(send_callback, some_object)
|
||||
|
||||
# Again optionally, a time limit can be specified in this case as follow:
|
||||
mydwr.send(send_callback, some_object, 10)
|
||||
# In that case, if no answer / error is received after 10 seconds (the value specified),
|
||||
# the callback is called with the request as parameter.
|
||||
# Testing for timeout case is done by using msg.is_request()
|
||||
def send_callback(msg, obj):
|
||||
if (msg.is_request()):
|
||||
print "Request timed out without answer:"
|
||||
else:
|
||||
print "Received answer:"
|
||||
msg.dump()
|
||||
print "Associated data:"
|
||||
obj
|
||||
return None
|
||||
|
||||
|
||||
# Set a result code in an answer message.
|
||||
mydwr = msg(buf)
|
||||
dwa = mydwr.create_answer()
|
||||
dwa.rescode_set() # This adds the DIAMETER_SUCCESS result code
|
||||
dwa.rescode_set("DIAMETER_LIMITED_SUCCESS" ) # This adds a different result code
|
||||
dwa.rescode_set("DIAMETER_LIMITED_SUCCESS", "Something went not so well" ) # This adds a different result code + specified Error-Message
|
||||
dwa.rescode_set("DIAMETER_INVALID_AVP", None, faulty_avp ) # This adds a Failed-AVP
|
||||
dwa.rescode_set("DIAMETER_SUCCESS", None, None, 1 ) # This adds origin information (see fd_msg_rescode_set's type_id for more info)
|
||||
|
||||
# Set the origin to local host
|
||||
mydwr.add_origin() # adds Origin-Host & Origin-Realm
|
||||
mydwr.add_origin(1) # adds Origin-State-Id in addition.
|
||||
|
||||
|
||||
############# DISPATCH (aka. server application) ############
|
||||
|
||||
# As for sessions, only one dispatch handler can be registered in this extension at the moment.
|
||||
# The callback for the handler has the following syntax:
|
||||
def dispatch_cb_model(inmsg, inavp, insession):
|
||||
print "Callback trigged on message: "
|
||||
inmsg.dump()
|
||||
# inavp is None or the AVP that trigged the callback, depending on how it was registered.
|
||||
if inavp:
|
||||
print "From the following AVP:"
|
||||
inavp.dump()
|
||||
else:
|
||||
print "No AVP"
|
||||
# Session is provided only if a Session-Id is in the message
|
||||
if insession:
|
||||
print "The session is: ", insession.getsid()
|
||||
else:
|
||||
print "No session"
|
||||
# Now, for the return value.
|
||||
# This callback must return 3 elements:
|
||||
# - an integer which is interpreted as an error code (errno.h)
|
||||
# - a message or None, depending on the next item
|
||||
# - an enum disp_action value, with the same meaning as in C (see libfreeDiameter.h)
|
||||
del inmsg
|
||||
return [ 0, None, DISP_ACT_CONT ]
|
||||
|
||||
|
||||
### Example use: rebuild the server-side of test_app.fdx in python
|
||||
|
||||
# The following block defines the dictionary objects from the test_app.fdx application that we use on the remote peer
|
||||
gdict = cvar.fd_g_config.cnf_dict
|
||||
d_si = gdict.search ( DICT_AVP, AVP_BY_NAME, "Session-Id" )
|
||||
d_oh = gdict.search ( DICT_AVP, AVP_BY_NAME, "Origin-Host" )
|
||||
d_or = gdict.search ( DICT_AVP, AVP_BY_NAME, "Origin-Realm" )
|
||||
d_dh = gdict.search ( DICT_AVP, AVP_BY_NAME, "Destination-Host" )
|
||||
d_dr = gdict.search ( DICT_AVP, AVP_BY_NAME, "Destination-Realm" )
|
||||
d_rc = gdict.search ( DICT_AVP, AVP_BY_NAME, "Result-Code" )
|
||||
d_vnd = gdict.new_obj(DICT_VENDOR, dict_vendor_data(999999, "app_test_py vendor") )
|
||||
d_app = gdict.new_obj(DICT_APPLICATION, dict_application_data(0xffffff, "app_test_py appli"), d_vnd)
|
||||
d_req = gdict.new_obj(DICT_COMMAND, dict_cmd_data(0xfffffe, "Test_py-Request", 1), d_app)
|
||||
d_ans = gdict.new_obj(DICT_COMMAND, dict_cmd_data(0xfffffe, "Test_py-Answer", 0), d_app)
|
||||
d_avp = gdict.new_obj(DICT_AVP, dict_avp_data(0xffffff, "app_test_py avp", AVP_TYPE_INTEGER32, 999999 ))
|
||||
gdict.new_obj(DICT_RULE, dict_rule_data(d_si, RULE_FIXED_HEAD, 1, 1), d_req)
|
||||
gdict.new_obj(DICT_RULE, dict_rule_data(d_si, RULE_FIXED_HEAD, 1, 1), d_ans)
|
||||
gdict.new_obj(DICT_RULE, dict_rule_data(d_avp, RULE_REQUIRED, 1, 1), d_req)
|
||||
gdict.new_obj(DICT_RULE, dict_rule_data(d_avp, RULE_REQUIRED, 1, 1), d_ans)
|
||||
gdict.new_obj(DICT_RULE, dict_rule_data(d_oh, RULE_REQUIRED, 1, 1), d_req)
|
||||
gdict.new_obj(DICT_RULE, dict_rule_data(d_oh, RULE_REQUIRED, 1, 1), d_ans)
|
||||
gdict.new_obj(DICT_RULE, dict_rule_data(d_or, RULE_REQUIRED, 1, 1), d_req)
|
||||
gdict.new_obj(DICT_RULE, dict_rule_data(d_or, RULE_REQUIRED, 1, 1), d_ans)
|
||||
gdict.new_obj(DICT_RULE, dict_rule_data(d_dr, RULE_REQUIRED, 1, 1), d_req)
|
||||
gdict.new_obj(DICT_RULE, dict_rule_data(d_dh, RULE_OPTIONAL, 0, 1), d_req)
|
||||
gdict.new_obj(DICT_RULE, dict_rule_data(d_rc, RULE_REQUIRED, 1, 1), d_ans)
|
||||
|
||||
# Now, create the Test_app server callback:
|
||||
def test_app_cb(inmsg, inavp, insession):
|
||||
tval = inmsg.search(d_avp).header().avp_value.u32
|
||||
print "Py ECHO Test message from '%s' with test value %x, replying..." % (inmsg.search(d_oh).header().avp_value.os.as_str(), tval)
|
||||
answ = inmsg.create_answer()
|
||||
answ.rescode_set()
|
||||
answ.add_origin()
|
||||
ta = avp(d_avp, AVPFL_SET_BLANK_VALUE)
|
||||
ta.header().avp_value.u32 = tval
|
||||
answ.add_child(ta)
|
||||
return [ 0, answ, DISP_ACT_SEND ]
|
||||
|
||||
# Register the callback for dispatch thread:
|
||||
hdl = disp_hdl(test_app_cb, DISP_HOW_CC, disp_when(d_app, d_req)) # disp_when() takes 0 to 4 arguments as follow: (app=NULL, cmd=NULL, avp=NULL, val=NULL)
|
||||
|
||||
# Don't forget to register the application in the daemon for CER/CEA capabilities.
|
||||
fd_disp_app_support ( d_app, d_vnd, 1, 0 )
|
||||
|
||||
|
||||
### For the fun, the client part of the test_app:
|
||||
|
||||
def receive_answer(ans, testval):
|
||||
try:
|
||||
tval = ans.search(d_avp).header().avp_value.u32
|
||||
except:
|
||||
print "Error in receive_answer: no Test-AVP included"
|
||||
tval = 0
|
||||
try:
|
||||
print "Py RECV %x (expected: %x) Status: %d From: '%s'" % (tval, testval, ans.search(d_rc).header().avp_value.u32, ans.search(d_oh).header().avp_value.os.as_str())
|
||||
except:
|
||||
print "Error in receive_answer: Result-Code or Origin-Host are missing"
|
||||
del ans
|
||||
return None
|
||||
|
||||
import random
|
||||
|
||||
def send_query(destrealm="localdomain"):
|
||||
qry = msg(d_req)
|
||||
sess = session()
|
||||
tv = random.randint(1, 1<<32)
|
||||
# Session-Id
|
||||
a = avp(d_si, AVPFL_SET_BLANK_VALUE)
|
||||
a.header().avp_value.os = sess.getsid()
|
||||
qry.add_child(a)
|
||||
# Destination-Realm
|
||||
a = avp(d_dr, AVPFL_SET_BLANK_VALUE)
|
||||
a.header().avp_value.os = destrealm
|
||||
qry.add_child(a)
|
||||
# Origin-Host, Origin-Realm
|
||||
qry.add_origin()
|
||||
# Test-AVP
|
||||
a = avp(d_avp, AVPFL_SET_BLANK_VALUE)
|
||||
a.header().avp_value.u32 = tv
|
||||
qry.add_child(a)
|
||||
print "Py SEND %x to '%s'" % (tv, destrealm)
|
||||
qry.send(receive_answer, tv)
|
||||
|
||||
send_query()
|
||||
|
||||
|
||||
############# FIFO queues ############
|
||||
|
||||
myqueue = fifo()
|
||||
|
||||
# enqueue any object
|
||||
myqueue.post(3)
|
||||
myqueue.post("blah")
|
||||
myqueue.post( [ 3, 2 ] )
|
||||
|
||||
# Simple get (blocks when the queue is empty)
|
||||
myqueue.get()
|
||||
|
||||
# Try get: returns the next object, or None if the queue is empty
|
||||
myqueue.tryget()
|
||||
|
||||
# timed get: like get, but returns None after x seconds
|
||||
myqueue.timedget(3)
|
||||
|
||||
# Show the number of items in the queue
|
||||
myqueue.length()
|
||||
|
||||
|
||||
## Variants:
|
||||
# All the previous calls are suitable to queue Python objects.
|
||||
# In order to interact with objects queued / poped by C counterpart,
|
||||
# a second parameter must be passed to specify the object type,
|
||||
# as follow:
|
||||
ev = fd_event()
|
||||
ev.code = FDEV_DUMP_EXT
|
||||
cvar.fd_g_config.cnf_main_ev.post(ev, "struct fd_event *")
|
||||
|
||||
# Similarly, for *get, we can specify the structure that was queued:
|
||||
myqueue.get("struct fd_event *")
|
||||
myqueue.tryget("struct fd_event *")
|
||||
myqueue.timedget(3, "struct fd_event *")
|
||||
|
||||
del myqueue
|
||||
|
||||
|
||||
############# HOOKS ############
|
||||
|
||||
def my_hook_cb(type, msg, peer, other, oldpmd):
|
||||
print "callback type ", type, " called: ", msg, other, oldpmd
|
||||
return "this is the new pmd"
|
||||
|
||||
# Create a wrapped fd_hook_data_hdl:
|
||||
datahdl = fd_hook_data_hdl()
|
||||
|
||||
# Register the hook callback:
|
||||
hdl = fd_hook_hdl(1 << HOOK_MESSAGE_SENT, my_hook_cb, datahdl)
|
||||
|
||||
|
||||
|
||||
|
||||
############# PEERS ############
|
||||
|
||||
# Get the list of peers defined in the system
|
||||
# (we are supposed to readlock fd_g_peers_rw before accessing this list)
|
||||
cvar.fd_g_peers_rw.rdlock()
|
||||
peers = cvar.fd_g_peers.enum_as("struct peer_hdr *")
|
||||
cvar.fd_g_peers_rw.unlock()
|
||||
for p in peers:
|
||||
print "Peer:", p.info.pi_diamid
|
||||
|
||||
|
||||
# Create a new peer
|
||||
np = peer_info()
|
||||
np.pi_diamid = "nas.localdomain"
|
||||
np.config.pic_flags.pro4 = PI_P4_TCP
|
||||
|
||||
|
||||
# Add this peer into the framework.
|
||||
np.add()
|
||||
|
||||
# It is possible to specify a callback for when the connection completes or fails with this peer.
|
||||
# The prototype is as follow:
|
||||
def add_cb(peer):
|
||||
if peer:
|
||||
if peer.runtime.pir_state == STATE_OPEN:
|
||||
print "Connection to peer '%s' completed" % (peer.pi_diamid)
|
||||
# can find more information in peer.runtime.*
|
||||
else:
|
||||
print "Connection to peer '%s' failed (state:%d)" % (peer.pi_diamid, peer.runtime.pir_state)
|
||||
else:
|
||||
print "The peer has been destroyed before it completed the connection."
|
||||
|
||||
# Then add the peer like this:
|
||||
np.add(add_cb)
|
||||
|
||||
|
||||
# Search a peer by its diameter id (returns a peer_hdr object if found) -- similar to fd_peer_getbyid
|
||||
p = peer_search("nas.domain.aaa")
|
||||
|
||||
|
||||
## Validation callback (see fd_peer_validate_register documentation)
|
||||
|
||||
# cb2 prototype:
|
||||
def my_validate_cb2(pinfo):
|
||||
print "Cb2 callback trigged for peer %s" % (pinfo.pi_diamid)
|
||||
# Usually, this would be used only to check some TLS properties,
|
||||
# which is not really possible yet through the python interpreter...
|
||||
return 0 # return an error code if the peer is not validated
|
||||
|
||||
# cb prototype:
|
||||
def my_validate_cb(pinfo):
|
||||
print "Validate callback trigged for peer %s" % (pinfo.pi_diamid)
|
||||
# If the peer is not allowed to connect:
|
||||
#return -1
|
||||
# If the peer is authorized:
|
||||
#return 1
|
||||
# In addition, if IPsec is allowed,
|
||||
#pinfo.config.pic_flags.sec = PI_SEC_NONE
|
||||
# If no decision has been made:
|
||||
#return 0
|
||||
# If the peer is temporarily authorized but a second callback must be called after TLS negociation:
|
||||
return my_validate_cb2
|
||||
|
||||
# Register the callback, it will be called on new incoming connections.
|
||||
peer_validate_register(my_validate_cb)
|
||||
|
||||
|
||||
|
||||
############# ENDPOINTS ############
|
||||
|
||||
ep = fd_endpoint("129.168.168.192")
|
||||
|
||||
# with port:
|
||||
ep = fd_endpoint("129.168.168.192", 3868)
|
||||
|
||||
# With different flags:
|
||||
ep = fd_endpoint("129.168.168.192", 3868, EP_FL_PRIMARY)
|
||||
|
||||
# Add IP information for the peer
|
||||
np = peer_info()
|
||||
ep.add_merge(np.pi_endpoints)
|
||||
fd_ep_dump(0, np.pi_endpoints)
|
||||
|
||||
|
||||
|
||||
############# POSIX functions wrappers ############
|
||||
|
||||
# The interface also provides wrappers around base POSIX
|
||||
# synchronization functions:
|
||||
|
||||
m = pthread_mutex_t()
|
||||
m.lock()
|
||||
m.unlock()
|
||||
|
||||
c = pthread_cond_t()
|
||||
c.signal()
|
||||
c.broadcast()
|
||||
c.wait(m)
|
||||
c.timedwait(m, 5) # it takes a relative time
|
||||
|
||||
r = pthread_rwlock_t()
|
||||
r.rdlock()
|
||||
r.unlock()
|
||||
r.wrlock()
|
||||
15
plat/diameter/doc/dict_legacy_xml.conf.sample
Normal file
15
plat/diameter/doc/dict_legacy_xml.conf.sample
Normal file
@@ -0,0 +1,15 @@
|
||||
# This file documents the configuration format for the dict_legacy_xml.fdx freeDiameter extension.
|
||||
# In order to load this extension, please refer to main freeDiameter.conf manual.
|
||||
|
||||
# This extension allows the use of Diameter dictionary files in XML format,
|
||||
# as roughly specified in draft-frascone-xml-dictionary-00.
|
||||
# (the actual format is the one from OpenDiameter latest version)
|
||||
# Note that this format, although more widely used, is less efficient than the
|
||||
# internal freeDiameter format. It is recommended when possible to use the later.
|
||||
|
||||
# You may refer to the contrib/dict_legacy/README file for information on where to find such resources.
|
||||
|
||||
# This file simply consists in a list of XML dictionary files that must be parsed.
|
||||
# Example:
|
||||
# "/etc/freeDiameter/dictionary.xml";
|
||||
|
||||
13
plat/diameter/doc/eap_tls_plugin.diameap.conf.sample
Normal file
13
plat/diameter/doc/eap_tls_plugin.diameap.conf.sample
Normal file
@@ -0,0 +1,13 @@
|
||||
#### a sample configuration file for EAP-TLS
|
||||
|
||||
#Certificate and Private key files
|
||||
#Cred = "<Path to certificate>" : "<Path to private Key>";
|
||||
|
||||
#CA file
|
||||
#CA = "<Path to CA file>";
|
||||
|
||||
#CRL file
|
||||
#CRL = "<Path to CRL file>";
|
||||
|
||||
#Enable/disable checking certificate's CN
|
||||
check_cert_cn_username = 1;
|
||||
33
plat/diameter/doc/echodrop.rgwx.conf.sample
Normal file
33
plat/diameter/doc/echodrop.rgwx.conf.sample
Normal file
@@ -0,0 +1,33 @@
|
||||
# Sample configuration file for the echodrop.rgwx plugin of RADIUS/Diameter translation agent.
|
||||
#
|
||||
# This plugin allows to easily specify the following handling of RADIUS attributes
|
||||
# received in a RADIUS request:
|
||||
# - ECHO: the attribute will be copied verbatim in the RADIUS answer.
|
||||
# - DROP: the attribute is discarded.
|
||||
#
|
||||
# In both cases, the attribute is NOT translated in Diameter message.
|
||||
#
|
||||
# The format of this file is:
|
||||
# <action> CODE <code> [ VENDOR <vid> [ TLV <type> | EXT <ext-type> ] ];
|
||||
# Where:
|
||||
# <action>: is either DROP or ECHO.
|
||||
# <code> : is a (decimal) integer between 0 and 255, and designates the type of the attribute.
|
||||
#
|
||||
# The remaining of the line is optional, and should only be used
|
||||
# with lines containing "CODE 26" (Vendor-Specific Attribute)
|
||||
# <vid> : a Vendor value (32 bit), see RFC2865 section 5.26 for detail.
|
||||
#
|
||||
# <type> : The attribute is interpreted as TLV (rfc3865, section 5.26)
|
||||
# and we match only this "vendor type" value (8 bits).
|
||||
#
|
||||
# <ext-type>: NOTE: THIS OPTION IS NOT SUPPORTED PROPERLY YET!!!!
|
||||
# The attribute is interpreted as extended attribute (draft-ietf-radext-extended-attributes-08)
|
||||
# and we match only this "Ext-Type" value (16 bits).
|
||||
# This option should only be used with "CODE 26 VENDOR 0".
|
||||
#
|
||||
# Note that the Proxy-State (code 33) attribute is handled directly as an ECHO parameter by the gateway core.
|
||||
|
||||
# Examples:
|
||||
# DROP code 18 ; # Reply-Message attribute, should not be included in requests
|
||||
# DROP code 26 vendor 9 ; # Drop any Cisco-specific attribute
|
||||
# ECHO code 26 vendor 0 ext 256 ; # Echo any extended attribute with the type 256.
|
||||
252
plat/diameter/doc/freediameter.conf.sample
Normal file
252
plat/diameter/doc/freediameter.conf.sample
Normal file
@@ -0,0 +1,252 @@
|
||||
# This is a sample configuration file for freeDiameter daemon.
|
||||
|
||||
# Most of the options can be omitted, as they default to reasonable values.
|
||||
# Only TLS-related options must be configured properly in usual setups.
|
||||
|
||||
# It is possible to use "include" keyword to import additional files
|
||||
# e.g.: include "/etc/freeDiameter.d/*.conf"
|
||||
# This is exactly equivalent as copy & paste the content of the included file(s)
|
||||
# where the "include" keyword is found.
|
||||
|
||||
|
||||
##############################################################
|
||||
## 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
|
||||
#Identity = "aaa.koganei.freediameter.net";
|
||||
|
||||
# The Diameter Realm of this daemon.
|
||||
# Default: the domain part of Identity (after the first dot).
|
||||
#Realm = "koganei.freediameter.net";
|
||||
|
||||
##############################################################
|
||||
## Transport protocol configuration
|
||||
|
||||
# The port this peer is listening on for incoming connections (TCP and SCTP).
|
||||
# Default: 3868. Use 0 to disable.
|
||||
#Port = 3868;
|
||||
|
||||
# The port this peer is listening on for incoming TLS-protected connections (TCP and SCTP).
|
||||
# See TLS_old_method for more information about TLS flavours.
|
||||
# Note: we use TLS/SCTP instead of DTLS/SCTP at the moment. This will change in future version of freeDiameter.
|
||||
# Default: 5868. Use 0 to disable.
|
||||
#SecPort = 5868;
|
||||
|
||||
# Use RFC3588 method for TLS protection, where TLS is negociated after CER/CEA exchange is completed
|
||||
# on the unsecure connection. The alternative is RFC6733 mechanism, where TLS protects also the
|
||||
# CER/CEA exchange on a dedicated secure port.
|
||||
# This parameter only affects outgoing connections.
|
||||
# The setting can be also defined per-peer (see Peers configuration section).
|
||||
# Default: use RFC6733 method with separate port for TLS.
|
||||
#TLS_old_method;
|
||||
|
||||
# Disable use of TCP protocol (only listen and connect over SCTP)
|
||||
# Default : TCP enabled
|
||||
#No_TCP;
|
||||
|
||||
# Disable use of SCTP protocol (only listen and connect over TCP)
|
||||
# Default : SCTP enabled
|
||||
#No_SCTP;
|
||||
# This option is ignored if freeDiameter is compiled with DISABLE_SCTP option.
|
||||
|
||||
# Prefer TCP instead of SCTP for establishing new connections.
|
||||
# This setting may be overwritten per peer in peer configuration blocs.
|
||||
# Default : SCTP is attempted first.
|
||||
#Prefer_TCP;
|
||||
|
||||
# Default number of streams per SCTP associations.
|
||||
# This setting may be overwritten per peer basis.
|
||||
# Default : 30 streams
|
||||
#SCTP_streams = 30;
|
||||
|
||||
##############################################################
|
||||
## Endpoint 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 the server must bind to
|
||||
# Default : listen on all addresses available.
|
||||
#ListenOn = "202.249.37.5";
|
||||
#ListenOn = "2001:200:903:2::202:1";
|
||||
#ListenOn = "fe80::21c:5ff:fe98:7d62%eth0";
|
||||
|
||||
|
||||
##############################################################
|
||||
## Server configuration
|
||||
|
||||
# How many Diameter peers are allowed to be connecting at the same time ?
|
||||
# This parameter limits the number of incoming connections from the time
|
||||
# the connection is accepted until the first CER is received.
|
||||
# Default: 5 unidentified clients in paralel.
|
||||
#ThreadsPerServer = 5;
|
||||
|
||||
##############################################################
|
||||
## TLS Configuration
|
||||
|
||||
# TLS is managed by the GNUTLS library in the freeDiameter daemon.
|
||||
# You may find more information about parameters and special behaviors
|
||||
# in the relevant documentation.
|
||||
# http://www.gnu.org/software/gnutls/manual/
|
||||
|
||||
# Credentials of the local peer
|
||||
# The X509 certificate and private key file to use for the local peer.
|
||||
# The files must contain PKCS-1 encoded RSA key, in PEM format.
|
||||
# (These parameters are passed to gnutls_certificate_set_x509_key_file function)
|
||||
# Default : NO DEFAULT
|
||||
#TLS_Cred = "<x509 certif file.PEM>" , "<x509 private key file.PEM>";
|
||||
TLS_Cred = "/etc/ssl/certs/freeDiameter.pem", "/etc/ssl/private/freeDiameter.key";
|
||||
|
||||
# Certificate authority / trust anchors
|
||||
# The file containing the list of trusted Certificate Authorities (PEM list)
|
||||
# (This parameter is passed to gnutls_certificate_set_x509_trust_file function)
|
||||
# The directive can appear several times to specify several files.
|
||||
# Default : GNUTLS default behavior
|
||||
#TLS_CA = "<file.PEM>";
|
||||
|
||||
# Certificate Revocation List file
|
||||
# The information about revoked certificates.
|
||||
# The file contains a list of trusted CRLs in PEM format. They should have been verified before.
|
||||
# (This parameter is passed to gnutls_certificate_set_x509_crl_file function)
|
||||
# Note: openssl CRL format might have interoperability issue with GNUTLS format.
|
||||
# Default : GNUTLS default behavior
|
||||
#TLS_CRL = "<file.PEM>";
|
||||
|
||||
# GNU TLS Priority string
|
||||
# This string allows to configure the behavior of GNUTLS key exchanges
|
||||
# algorithms. See gnutls_priority_init function documentation for information.
|
||||
# You should also refer to the Diameter required TLS support here:
|
||||
# http://tools.ietf.org/html/rfc6733#section-13.1
|
||||
# Default : "NORMAL"
|
||||
# Example: TLS_Prio = "NONE:+VERS-TLS1.1:+AES-128-CBC:+RSA:+SHA1:+COMP-NULL";
|
||||
#TLS_Prio = "NORMAL";
|
||||
|
||||
# Diffie-Hellman parameters size
|
||||
# Set the number of bits for generated DH parameters
|
||||
# Valid value should be 768, 1024, 2048, 3072 or 4096.
|
||||
# (This parameter is passed to gnutls_dh_params_generate2 function,
|
||||
# it usually should match RSA key size)
|
||||
# Default : 1024
|
||||
#TLS_DH_Bits = 1024;
|
||||
|
||||
# Alternatively, you can specify a file to load the PKCS#3 encoded
|
||||
# DH parameters directly from. This accelerates the daemon start
|
||||
# but is slightly less secure. If this file is provided, the
|
||||
# TLS_DH_Bits parameters has no effect.
|
||||
# Default : no default.
|
||||
#TLS_DH_File = "<file.PEM>";
|
||||
|
||||
|
||||
##############################################################
|
||||
## 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;
|
||||
|
||||
# Number of server threads that can handle incoming messages at the same time.
|
||||
# Default: 4
|
||||
#AppServThreads = 4;
|
||||
|
||||
# Other applications are configured by loaded extensions.
|
||||
|
||||
##############################################################
|
||||
## Extensions configuration
|
||||
|
||||
# The freeDiameter framework merely provides support for
|
||||
# Diameter Base Protocol. The specific application behaviors,
|
||||
# as well as advanced functions, 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" ] ;
|
||||
#
|
||||
# Examples:
|
||||
#LoadExtension = "extensions/sample.fdx";
|
||||
#LoadExtension = "extensions/sample.fdx":"conf/sample.conf";
|
||||
|
||||
# Extensions are named as follow:
|
||||
# dict_* for extensions that add content to the dictionary definitions.
|
||||
# dbg_* for extensions useful only to retrieve more information on the framework execution.
|
||||
# acl_* : Access control list, to control which peers are allowed to connect.
|
||||
# rt_* : routing extensions that impact how messages are forwarded to other peers.
|
||||
# app_* : applications, these extensions usually register callbacks to handle specific messages.
|
||||
# test_* : dummy extensions that are useful only in testing environments.
|
||||
|
||||
|
||||
# The dbg_msg_dump.fdx extension allows you to tweak the way freeDiameter displays some
|
||||
# information about some events. This extension does not actually use a configuration file
|
||||
# but receives directly a parameter in the string passed to the extension. Here are some examples:
|
||||
## LoadExtension = "dbg_msg_dumps.fdx" : "0x1111"; # Removes all default hooks, very quiet even in case of errors.
|
||||
## LoadExtension = "dbg_msg_dumps.fdx" : "0x2222"; # Display all events with few details.
|
||||
## LoadExtension = "dbg_msg_dumps.fdx" : "0x0080"; # Dump complete information about sent and received messages.
|
||||
# The four digits respectively control: connections, routing decisions, sent/received messages, errors.
|
||||
# The values for each digit are:
|
||||
# 0 - default - keep the default behavior
|
||||
# 1 - quiet - remove any specific log
|
||||
# 2 - compact - display only a summary of the information
|
||||
# 4 - full - display the complete information on a single long line
|
||||
# 8 - tree - display the complete information in an easier to read format spanning several lines.
|
||||
|
||||
|
||||
##############################################################
|
||||
## Peers configuration
|
||||
|
||||
# The local server listens for incoming connections. By default,
|
||||
# all unknown connecting peers are rejected. Extensions can override this behavior (e.g., acl_wl).
|
||||
#
|
||||
# In addition to incoming connections, the local peer can
|
||||
# be configured to establish and maintain connections to some
|
||||
# Diameter nodes and allow connections from these nodes.
|
||||
# This is achieved with the ConnectPeer directive described below.
|
||||
#
|
||||
# Note that the configured Diameter Identity MUST match
|
||||
# the information received inside CEA, or the connection will be aborted.
|
||||
#
|
||||
# Format:
|
||||
#ConnectPeer = "diameterid" [ { parameter1; parameter2; ...} ] ;
|
||||
# Parameters that can be specified in the peer's parameter list:
|
||||
# No_TCP; No_SCTP; No_IP; No_IPv6; Prefer_TCP; TLS_old_method;
|
||||
# No_TLS; # assume transparent security instead of TLS. DTLS is not supported yet (will change in future versions).
|
||||
# Port = 5868; # The port to connect to
|
||||
# TcTimer = 30;
|
||||
# TwTimer = 30;
|
||||
# ConnectTo = "202.249.37.5";
|
||||
# ConnectTo = "2001:200:903:2::202:1";
|
||||
# TLS_Prio = "NORMAL";
|
||||
# Realm = "realm.net"; # Reject the peer if it does not advertise this realm.
|
||||
# Examples:
|
||||
#ConnectPeer = "aaa.wide.ad.jp";
|
||||
#ConnectPeer = "old.diameter.serv" { TcTimer = 60; TLS_old_method; No_SCTP; Port=3868; } ;
|
||||
|
||||
|
||||
##############################################################
|
||||
47
plat/diameter/doc/rt_busypeers.conf.sample
Normal file
47
plat/diameter/doc/rt_busypeers.conf.sample
Normal file
@@ -0,0 +1,47 @@
|
||||
# This file contains information for configuring the rt_busypeers extension.
|
||||
# To find how to have freeDiameter load this extension, please refer to the freeDiameter documentation.
|
||||
#
|
||||
# The rt_busypeers extension has two purposes.
|
||||
# - when the local peer receives an error DIAMETER_TOO_BUSY from a peer,
|
||||
# this extension catchs this error and attempts to retransmit the query to another peer if it makes sense, i.e.:
|
||||
# * the peer issuing the error is not the peer referenced in the Destination-Host AVP of the message,
|
||||
# * we have a direct link with the peer that issued the error (see parameter RetryDistantPeers below)
|
||||
#
|
||||
# - When a request is forwarded by the local peer, start a timer and if the corresponding answer/error has
|
||||
# not been received within RelayTimeout seconds, either send to another peer or return a DIAMETER_TOO_BUSY
|
||||
# error, depending on the RetryMaxPeers parameter.
|
||||
#
|
||||
# This extension is mainly useful for Diameter agents, for Diameter clients it is recommended to
|
||||
# implement this logic directly in the client application.
|
||||
|
||||
|
||||
# Parameter: SkipTooBusyErrors
|
||||
# If defined, this parameter disables the handling of Diameter Errors message with a Result-Code set to DIAMETER_TOO_BUSY in this extension.
|
||||
# When this parameter is defined, the parameter RetryDistantPeer has no effect.
|
||||
# Default: parameter is not defined.
|
||||
#SkipTooBusyErrors;
|
||||
|
||||
|
||||
# Parameter: RetryDistantPeers
|
||||
# By default, the extension only retries to send messages if the peer that issued the DIAMETER_TOO_BUSY error is directly connected to
|
||||
# the local peer (not through a Diameter agent). This avoids the situation where the message is sent to a different relay that will deliver
|
||||
# to the same busy peer afterwards. If the parameter is defined, then the extension will also retry sending messages for errors generated in
|
||||
# distant peers. This should increase the chance that the message is delivered, but also can increase the load of the network unnecessarily.
|
||||
# Default: parameter is not defined.
|
||||
#RetryDistantPeers;
|
||||
|
||||
|
||||
# Parameter: RetryMaxPeers
|
||||
# This parameter specifies the limit on the number of times a request can be re-sent to a different peer, before the local relay gives up and
|
||||
# forwards the error to upstream.
|
||||
# Default: 0, meaning all possible candidates are attempted before give up.
|
||||
#RetryMaxPeers=0;
|
||||
|
||||
|
||||
# Parameter: RelayTimeout
|
||||
# If the value of this parameter is not 0, it specifies the number of milliseconds (1/1000 s) that the local relay waits for an answer to a
|
||||
# forwarded request before considering the remote peer is busy and taking corrective action (similar as if that relay had returned TOO_BUSY status).
|
||||
# Note: this parameter does not apply for requests issued locally. In that case, the extension issuing the request should directly specify the timeout.
|
||||
# Default: 0, meaning that there is no timeout parameter.
|
||||
#RelayTimeout=0;
|
||||
|
||||
91
plat/diameter/doc/rt_default.conf.sample
Normal file
91
plat/diameter/doc/rt_default.conf.sample
Normal file
@@ -0,0 +1,91 @@
|
||||
# This file contains the configuration for the rt_default extension of freeDiameter.
|
||||
#
|
||||
# This extension provides configurable routing properties for freeDiameter.
|
||||
|
||||
# Lines starting with a # are comments and ignored.
|
||||
|
||||
##############################################################################
|
||||
# The freeDiameter daemon will not allow forwarding a message to a peer that:
|
||||
# - already forwarded the message (appear as Route-Record inside the message)
|
||||
# - connection is not in STATE_OPEN state.
|
||||
# We call here "eligible peer" a peer that is not screened out by one of these criteria.
|
||||
#
|
||||
# Even if a peer is specified as route for a message here, the daemon may
|
||||
# choose to send a message to another peer, or return a UNABLE_TO_DELIVER error, if that peer is not eligible
|
||||
# at the time where the message is to be forwarded.
|
||||
#
|
||||
# Note also that defining a peer here will not result in the daemon trying to establish
|
||||
# a connection to this peer. For this purpose, the peer must be defined in the main
|
||||
# configuration (ConnectPeer), or connection established through other means (e.g. dynamic peer
|
||||
# discovery extension).
|
||||
#
|
||||
# The default forwarding behavior of freeDiameter is:
|
||||
# - if the message contains a Destination-Host AVP, and the designated peer is an eligible candidate, send to this peer.
|
||||
# - if a peer does not support the message application or Relay application, give it a penalty for this message
|
||||
# (it means that unless overwritten by an extension, the message will not be sent to that peer)
|
||||
# - if one of the eligible peer advertised a realm matching the message's Destination-Realm, send to this peer.
|
||||
#
|
||||
# The mechanism is as follow:
|
||||
# - the daemon builds a list of eligible peers, then attributes a score to these peers (see enum fd_rt_out_score in freeDiameter.h)
|
||||
# - any number of extensions can register a callback and modify the score
|
||||
# - after all callbacks have been called, the message is sent to the peer with the higher score. If an error is received, it is retried to the next peer in the list, and so on,
|
||||
# until the list is empty. In such situation, an error UNABLE_TO_DELIVER is generated.
|
||||
#
|
||||
# This extension allows to modify the score of some peers based on some criteria of the message.
|
||||
#
|
||||
# Finally, please note that the freeDiameter daemon does not support REDIRECT indications natively.
|
||||
# You have to load the rt_redir extension to add this support.
|
||||
##############################################################################
|
||||
|
||||
# This file contains a list of RULE elements.
|
||||
# Each RULE is made of three components:
|
||||
# - a CRITERIA, which specifies which messages the RULE apply to.
|
||||
# - a TARGET string, that specifies which peer(s) in the eligible list the rule is applied to
|
||||
# - and a SCORE, that is added to the matching peer's current score.
|
||||
#
|
||||
# In the following definitions, "STR/REG" stands for:
|
||||
# - a quoted string "some.peer" that will match exactly this string (case-insensitive), or
|
||||
# - a bracket-quoted string ["some regex"] that will be interpreted as a POSIX extended regular expression (case-sensitive), and attempt to match the string.
|
||||
#
|
||||
# The RULE is specified as:
|
||||
# CRITERIA : TARGET += SCORE ;
|
||||
#
|
||||
# The CRITERIA can be:
|
||||
# * -> matches any message.
|
||||
# oh="STR/REG" -> selects the message if the string or regular expression matches the message's Origin-Host AVP content
|
||||
# or="STR/REG" -> idem with Origin-Realm
|
||||
# dh="STR/REG" -> idem with Destination-Host
|
||||
# dr="STR/REG" -> idem with Destination-Realm
|
||||
# un="STR/REG" -> idem with User-Name
|
||||
# si="STR/REG" -> idem with Session-Id
|
||||
#
|
||||
# The TARGET is also of a similar form:
|
||||
# "STR/REG" -> Will apply the score to this peer if its Diameter-Id is matched by the string or regular expression.
|
||||
# rlm="STR/REG" -> Idem with the peer's advertized Diameter-Realm.
|
||||
#
|
||||
# The SCORE is either numeric (positive or negative), or one of the following constants (see values in libfdcore.h):
|
||||
# NO_DELIVERY
|
||||
# DEFAULT
|
||||
# DEFAULT_REALM
|
||||
# REALM
|
||||
# REDIR_HOST
|
||||
# REDIR_APP
|
||||
# REDIR_REALM
|
||||
# REDIR_REALM_APP
|
||||
# REDIR_USER
|
||||
# REDIR_SESSION
|
||||
# FINALDEST
|
||||
#
|
||||
#
|
||||
# Here are some examples:
|
||||
# 1) Rule to add a default next-hop peer to all messages:
|
||||
# * : "proxy.testbed.aaa" += DEFAULT ;
|
||||
#
|
||||
# 2) Rule to route messages for a given realm (realmA) through another realm (realmB):
|
||||
# dr="realmA" : rlm="realmB" += DEFAULT_REALM ;
|
||||
#
|
||||
# 3) Avoid sending messages with decorated NAI to the proxy A:
|
||||
# un=[".+!.+@.+"] : "proxy.A" += NO_DELIVERY ;
|
||||
|
||||
|
||||
|
||||
21
plat/diameter/doc/rt_ereg.conf.sample
Normal file
21
plat/diameter/doc/rt_ereg.conf.sample
Normal file
@@ -0,0 +1,21 @@
|
||||
# This file contains information for configuring the rt_ereg extension.
|
||||
# To find how to have freeDiameter load this extension, please refer to the freeDiameter documentation.
|
||||
#
|
||||
# The rt_ereg extension allows creation of routing rules based on AVP value matching regular expressions.
|
||||
|
||||
# First, one must indicate which AVP should be used for matching.
|
||||
# At the moment, only AVP with OCTETSTRING types are valid.
|
||||
# AVP = "User-Name";
|
||||
# This parameter is mandatory. There is no default value.
|
||||
|
||||
# Then a list of rules follow. A rule has this format:
|
||||
# "pattern" : "server" += score ;
|
||||
# Where:
|
||||
# pattern is the quoted-string regex to match,
|
||||
# server is the next hop in the routing list that will receive the
|
||||
# score, which can be positive or negative.
|
||||
# Example:
|
||||
# "[[:digit:]]*" : "serverA.example.net" += -3 ;
|
||||
# means that if the AVP value is only numeric, the ServerA will have its score decreased by 3 points.
|
||||
# (reminder: the server with the peer with the highest score gets the message)
|
||||
# Note that all rules are tested for each message that contain the AVP, not only the first match.
|
||||
87
plat/diameter/doc/single_host/CAGenerate/ca.chain.crt
Normal file
87
plat/diameter/doc/single_host/CAGenerate/ca.chain.crt
Normal file
@@ -0,0 +1,87 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 17253258667433909647 (0xef6fe358aa53dd8f)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: DC=com, DC=example, CN=Test Certifying CA
|
||||
Validity
|
||||
Not Before: Jun 18 16:54:51 2016 GMT
|
||||
Not After : Jun 18 16:54:51 2017 GMT
|
||||
Subject: DC=com, DC=example, CN=Test Certifying CA
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:e9:29:6f:b7:08:85:18:17:c4:7a:4c:de:89:29:
|
||||
28:01:07:ef:60:c9:f5:71:b2:40:51:b2:c5:be:dc:
|
||||
41:9c:e1:0f:ba:62:9e:5a:d2:58:1f:7b:71:aa:c3:
|
||||
e8:d7:b6:49:78:b8:1d:21:96:98:c6:8b:c3:95:47:
|
||||
45:58:c8:6c:e4:32:4c:53:a7:0f:97:e5:91:8b:66:
|
||||
a8:a6:17:89:1b:f3:33:05:40:34:1c:8d:f3:66:0c:
|
||||
0c:a7:cb:98:01:35:78:5d:bd:8d:d7:ee:62:bd:78:
|
||||
9b:14:69:2f:03:fd:99:b3:45:9e:a6:11:cf:e7:6f:
|
||||
9d:a2:ea:34:59:c2:57:82:0b:70:5f:f2:1d:a2:de:
|
||||
36:90:34:2a:81:0b:14:f2:c2:42:c0:19:44:05:11:
|
||||
d6:c4:e7:48:a6:64:1e:b5:87:ea:ce:d0:cc:1c:bb:
|
||||
37:71:30:a8:47:87:38:90:ae:4f:c6:3a:cb:32:a8:
|
||||
26:e4:01:cf:69:2c:e5:36:35:9c:52:15:08:ca:b9:
|
||||
2a:eb:d6:76:00:c2:6c:70:c4:10:23:12:43:9b:a9:
|
||||
31:6f:84:51:ef:1e:a7:e9:7d:20:3a:c6:34:f5:35:
|
||||
6c:36:b9:b6:e1:8c:2d:77:af:b1:d0:d0:e2:28:c7:
|
||||
93:f2:84:f5:8f:b1:5d:0d:05:e8:4a:5d:c7:b3:69:
|
||||
a3:73
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Key Identifier:
|
||||
5B:09:09:8C:18:28:52:5C:5B:39:E9:07:62:07:54:43:73:81:F1:33
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:5B:09:09:8C:18:28:52:5C:5B:39:E9:07:62:07:54:43:73:81:F1:33
|
||||
DirName:/DC=com/DC=example/CN=Test Certifying CA
|
||||
serial:EF:6F:E3:58:AA:53:DD:8F
|
||||
|
||||
X509v3 Key Usage:
|
||||
Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment, Key Agreement, Certificate Sign, CRL Sign
|
||||
X509v3 Basic Constraints: critical
|
||||
CA:TRUE
|
||||
Netscape Comment:
|
||||
Testing CA Certificate
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
34:24:3a:34:f7:8d:58:de:dc:b5:34:6e:06:ea:53:77:c9:9a:
|
||||
fe:7f:29:7f:3e:74:d1:f9:97:c4:7b:b5:0e:82:99:ac:89:03:
|
||||
a6:48:9e:17:f9:6f:06:eb:c2:93:33:de:45:82:8a:2d:4b:1a:
|
||||
4b:3c:30:36:6f:a2:b9:f9:d0:24:97:65:5c:82:19:0c:83:5e:
|
||||
ae:16:09:25:fa:83:5c:59:5c:18:83:8b:c8:e6:c2:77:c5:d0:
|
||||
1a:8c:95:6e:ba:18:a6:29:86:92:e7:8b:71:26:12:1b:1e:c7:
|
||||
3f:0a:de:28:95:0b:4e:02:2f:8f:56:83:f2:0d:0f:d0:54:f1:
|
||||
25:15:e8:3f:02:c1:2a:f7:cd:0a:07:51:85:c9:9a:3a:64:66:
|
||||
1e:25:4a:b0:ac:38:96:3e:db:36:04:e4:23:06:e5:93:f0:24:
|
||||
db:ff:60:1d:ce:eb:a2:37:f1:86:9f:a7:d2:23:f7:c7:9e:72:
|
||||
a8:20:87:2d:ca:37:7a:15:d7:d6:47:13:ce:58:0f:d8:6b:f3:
|
||||
34:2c:7d:42:01:bf:32:8d:65:62:af:e0:1f:6c:9f:04:07:6c:
|
||||
0d:f0:93:c3:67:f1:9a:73:a7:4f:82:8f:c8:05:7d:63:b3:48:
|
||||
a0:e2:3b:2e:da:c7:cb:05:91:32:59:1a:54:94:22:7b:01:92:
|
||||
9a:c4:c2:e7
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID/jCCAuagAwIBAgIJAO9v41iqU92PMA0GCSqGSIb3DQEBBQUAMEsxEzARBgoJ
|
||||
kiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMRswGQYDVQQD
|
||||
ExJUZXN0IENlcnRpZnlpbmcgQ0EwHhcNMTYwNjE4MTY1NDUxWhcNMTcwNjE4MTY1
|
||||
NDUxWjBLMRMwEQYKCZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhh
|
||||
bXBsZTEbMBkGA1UEAxMSVGVzdCBDZXJ0aWZ5aW5nIENBMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEA6SlvtwiFGBfEekzeiSkoAQfvYMn1cbJAUbLFvtxB
|
||||
nOEPumKeWtJYH3txqsPo17ZJeLgdIZaYxovDlUdFWMhs5DJMU6cPl+WRi2aopheJ
|
||||
G/MzBUA0HI3zZgwMp8uYATV4Xb2N1+5ivXibFGkvA/2Zs0WephHP52+douo0WcJX
|
||||
ggtwX/Idot42kDQqgQsU8sJCwBlEBRHWxOdIpmQetYfqztDMHLs3cTCoR4c4kK5P
|
||||
xjrLMqgm5AHPaSzlNjWcUhUIyrkq69Z2AMJscMQQIxJDm6kxb4RR7x6n6X0gOsY0
|
||||
9TVsNrm24Ywtd6+x0NDiKMeT8oT1j7FdDQXoSl3Hs2mjcwIDAQABo4HkMIHhMB0G
|
||||
A1UdDgQWBBRbCQmMGChSXFs56QdiB1RDc4HxMzB7BgNVHSMEdDBygBRbCQmMGChS
|
||||
XFs56QdiB1RDc4HxM6FPpE0wSzETMBEGCgmSJomT8ixkARkWA2NvbTEXMBUGCgmS
|
||||
JomT8ixkARkWB2V4YW1wbGUxGzAZBgNVBAMTElRlc3QgQ2VydGlmeWluZyBDQYIJ
|
||||
AO9v41iqU92PMAsGA1UdDwQEAwIB/jAPBgNVHRMBAf8EBTADAQH/MCUGCWCGSAGG
|
||||
+EIBDQQYFhZUZXN0aW5nIENBIENlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAA4IB
|
||||
AQA0JDo0941Y3ty1NG4G6lN3yZr+fyl/PnTR+ZfEe7UOgpmsiQOmSJ4X+W8G68KT
|
||||
M95FgootSxpLPDA2b6K5+dAkl2VcghkMg16uFgkl+oNcWVwYg4vI5sJ3xdAajJVu
|
||||
uhimKYaS54txJhIbHsc/Ct4olQtOAi+PVoPyDQ/QVPElFeg/AsEq980KB1GFyZo6
|
||||
ZGYeJUqwrDiWPts2BOQjBuWT8CTb/2AdzuuiN/GGn6fSI/fHnnKoIIctyjd6FdfW
|
||||
RxPOWA/Ya/M0LH1CAb8yjWVir+AfbJ8EB2wN8JPDZ/Gac6dPgo/IBX1js0ig4jsu
|
||||
2sfLBZEyWRpUlCJ7AZKaxMLn
|
||||
-----END CERTIFICATE-----
|
||||
BIN
plat/diameter/doc/single_host/CAGenerate/ca.crl
Normal file
BIN
plat/diameter/doc/single_host/CAGenerate/ca.crl
Normal file
Binary file not shown.
87
plat/diameter/doc/single_host/CAGenerate/ca.crt
Normal file
87
plat/diameter/doc/single_host/CAGenerate/ca.crt
Normal file
@@ -0,0 +1,87 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 17253258667433909647 (0xef6fe358aa53dd8f)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: DC=com, DC=example, CN=Test Certifying CA
|
||||
Validity
|
||||
Not Before: Jun 18 16:54:51 2016 GMT
|
||||
Not After : Jun 18 16:54:51 2017 GMT
|
||||
Subject: DC=com, DC=example, CN=Test Certifying CA
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:e9:29:6f:b7:08:85:18:17:c4:7a:4c:de:89:29:
|
||||
28:01:07:ef:60:c9:f5:71:b2:40:51:b2:c5:be:dc:
|
||||
41:9c:e1:0f:ba:62:9e:5a:d2:58:1f:7b:71:aa:c3:
|
||||
e8:d7:b6:49:78:b8:1d:21:96:98:c6:8b:c3:95:47:
|
||||
45:58:c8:6c:e4:32:4c:53:a7:0f:97:e5:91:8b:66:
|
||||
a8:a6:17:89:1b:f3:33:05:40:34:1c:8d:f3:66:0c:
|
||||
0c:a7:cb:98:01:35:78:5d:bd:8d:d7:ee:62:bd:78:
|
||||
9b:14:69:2f:03:fd:99:b3:45:9e:a6:11:cf:e7:6f:
|
||||
9d:a2:ea:34:59:c2:57:82:0b:70:5f:f2:1d:a2:de:
|
||||
36:90:34:2a:81:0b:14:f2:c2:42:c0:19:44:05:11:
|
||||
d6:c4:e7:48:a6:64:1e:b5:87:ea:ce:d0:cc:1c:bb:
|
||||
37:71:30:a8:47:87:38:90:ae:4f:c6:3a:cb:32:a8:
|
||||
26:e4:01:cf:69:2c:e5:36:35:9c:52:15:08:ca:b9:
|
||||
2a:eb:d6:76:00:c2:6c:70:c4:10:23:12:43:9b:a9:
|
||||
31:6f:84:51:ef:1e:a7:e9:7d:20:3a:c6:34:f5:35:
|
||||
6c:36:b9:b6:e1:8c:2d:77:af:b1:d0:d0:e2:28:c7:
|
||||
93:f2:84:f5:8f:b1:5d:0d:05:e8:4a:5d:c7:b3:69:
|
||||
a3:73
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Key Identifier:
|
||||
5B:09:09:8C:18:28:52:5C:5B:39:E9:07:62:07:54:43:73:81:F1:33
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:5B:09:09:8C:18:28:52:5C:5B:39:E9:07:62:07:54:43:73:81:F1:33
|
||||
DirName:/DC=com/DC=example/CN=Test Certifying CA
|
||||
serial:EF:6F:E3:58:AA:53:DD:8F
|
||||
|
||||
X509v3 Key Usage:
|
||||
Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment, Key Agreement, Certificate Sign, CRL Sign
|
||||
X509v3 Basic Constraints: critical
|
||||
CA:TRUE
|
||||
Netscape Comment:
|
||||
Testing CA Certificate
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
34:24:3a:34:f7:8d:58:de:dc:b5:34:6e:06:ea:53:77:c9:9a:
|
||||
fe:7f:29:7f:3e:74:d1:f9:97:c4:7b:b5:0e:82:99:ac:89:03:
|
||||
a6:48:9e:17:f9:6f:06:eb:c2:93:33:de:45:82:8a:2d:4b:1a:
|
||||
4b:3c:30:36:6f:a2:b9:f9:d0:24:97:65:5c:82:19:0c:83:5e:
|
||||
ae:16:09:25:fa:83:5c:59:5c:18:83:8b:c8:e6:c2:77:c5:d0:
|
||||
1a:8c:95:6e:ba:18:a6:29:86:92:e7:8b:71:26:12:1b:1e:c7:
|
||||
3f:0a:de:28:95:0b:4e:02:2f:8f:56:83:f2:0d:0f:d0:54:f1:
|
||||
25:15:e8:3f:02:c1:2a:f7:cd:0a:07:51:85:c9:9a:3a:64:66:
|
||||
1e:25:4a:b0:ac:38:96:3e:db:36:04:e4:23:06:e5:93:f0:24:
|
||||
db:ff:60:1d:ce:eb:a2:37:f1:86:9f:a7:d2:23:f7:c7:9e:72:
|
||||
a8:20:87:2d:ca:37:7a:15:d7:d6:47:13:ce:58:0f:d8:6b:f3:
|
||||
34:2c:7d:42:01:bf:32:8d:65:62:af:e0:1f:6c:9f:04:07:6c:
|
||||
0d:f0:93:c3:67:f1:9a:73:a7:4f:82:8f:c8:05:7d:63:b3:48:
|
||||
a0:e2:3b:2e:da:c7:cb:05:91:32:59:1a:54:94:22:7b:01:92:
|
||||
9a:c4:c2:e7
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID/jCCAuagAwIBAgIJAO9v41iqU92PMA0GCSqGSIb3DQEBBQUAMEsxEzARBgoJ
|
||||
kiaJk/IsZAEZFgNjb20xFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMRswGQYDVQQD
|
||||
ExJUZXN0IENlcnRpZnlpbmcgQ0EwHhcNMTYwNjE4MTY1NDUxWhcNMTcwNjE4MTY1
|
||||
NDUxWjBLMRMwEQYKCZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhh
|
||||
bXBsZTEbMBkGA1UEAxMSVGVzdCBDZXJ0aWZ5aW5nIENBMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEA6SlvtwiFGBfEekzeiSkoAQfvYMn1cbJAUbLFvtxB
|
||||
nOEPumKeWtJYH3txqsPo17ZJeLgdIZaYxovDlUdFWMhs5DJMU6cPl+WRi2aopheJ
|
||||
G/MzBUA0HI3zZgwMp8uYATV4Xb2N1+5ivXibFGkvA/2Zs0WephHP52+douo0WcJX
|
||||
ggtwX/Idot42kDQqgQsU8sJCwBlEBRHWxOdIpmQetYfqztDMHLs3cTCoR4c4kK5P
|
||||
xjrLMqgm5AHPaSzlNjWcUhUIyrkq69Z2AMJscMQQIxJDm6kxb4RR7x6n6X0gOsY0
|
||||
9TVsNrm24Ywtd6+x0NDiKMeT8oT1j7FdDQXoSl3Hs2mjcwIDAQABo4HkMIHhMB0G
|
||||
A1UdDgQWBBRbCQmMGChSXFs56QdiB1RDc4HxMzB7BgNVHSMEdDBygBRbCQmMGChS
|
||||
XFs56QdiB1RDc4HxM6FPpE0wSzETMBEGCgmSJomT8ixkARkWA2NvbTEXMBUGCgmS
|
||||
JomT8ixkARkWB2V4YW1wbGUxGzAZBgNVBAMTElRlc3QgQ2VydGlmeWluZyBDQYIJ
|
||||
AO9v41iqU92PMAsGA1UdDwQEAwIB/jAPBgNVHRMBAf8EBTADAQH/MCUGCWCGSAGG
|
||||
+EIBDQQYFhZUZXN0aW5nIENBIENlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAA4IB
|
||||
AQA0JDo0941Y3ty1NG4G6lN3yZr+fyl/PnTR+ZfEe7UOgpmsiQOmSJ4X+W8G68KT
|
||||
M95FgootSxpLPDA2b6K5+dAkl2VcghkMg16uFgkl+oNcWVwYg4vI5sJ3xdAajJVu
|
||||
uhimKYaS54txJhIbHsc/Ct4olQtOAi+PVoPyDQ/QVPElFeg/AsEq980KB1GFyZo6
|
||||
ZGYeJUqwrDiWPts2BOQjBuWT8CTb/2AdzuuiN/GGn6fSI/fHnnKoIIctyjd6FdfW
|
||||
RxPOWA/Ya/M0LH1CAb8yjWVir+AfbJ8EB2wN8JPDZ/Gac6dPgo/IBX1js0ig4jsu
|
||||
2sfLBZEyWRpUlCJ7AZKaxMLn
|
||||
-----END CERTIFICATE-----
|
||||
16
plat/diameter/doc/single_host/CAGenerate/ca.csr
Normal file
16
plat/diameter/doc/single_host/CAGenerate/ca.csr
Normal file
@@ -0,0 +1,16 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICkDCCAXgCAQAwSzETMBEGCgmSJomT8ixkARkWA2NvbTEXMBUGCgmSJomT8ixk
|
||||
ARkWB2V4YW1wbGUxGzAZBgNVBAMTElRlc3QgQ2VydGlmeWluZyBDQTCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAOkpb7cIhRgXxHpM3okpKAEH72DJ9XGy
|
||||
QFGyxb7cQZzhD7pinlrSWB97carD6Ne2SXi4HSGWmMaLw5VHRVjIbOQyTFOnD5fl
|
||||
kYtmqKYXiRvzMwVANByN82YMDKfLmAE1eF29jdfuYr14mxRpLwP9mbNFnqYRz+dv
|
||||
naLqNFnCV4ILcF/yHaLeNpA0KoELFPLCQsAZRAUR1sTnSKZkHrWH6s7QzBy7N3Ew
|
||||
qEeHOJCuT8Y6yzKoJuQBz2ks5TY1nFIVCMq5KuvWdgDCbHDEECMSQ5upMW+EUe8e
|
||||
p+l9IDrGNPU1bDa5tuGMLXevsdDQ4ijHk/KE9Y+xXQ0F6Epdx7Npo3MCAwEAAaAA
|
||||
MA0GCSqGSIb3DQEBBQUAA4IBAQCvHeXfLukUAajL7H52zH8cSbojf+r/Y3z1Gc6R
|
||||
sZ+tVTI/FVskjvhQ/tyHxktXVU8A5iXHD1aOE78dfNM9OTv9ys0k0/rD6lSAdWfE
|
||||
L9HgWll4hYm9a1DKEqPOuEIkj/p1sQkNgZUmUWyELvyp4safgD+h2ugmPBzis/hF
|
||||
je3q29+lhTe38GG91mGxhnHTJcsLF0Te0y4yv1JScryZ7uqnzjyrLxiJLRYGc2di
|
||||
7db1WmjtxDQUxclLkt6BBhVIi87K04S1hglY8mxlLiVdF0tEY4a/a1hLGs1Q4U8Z
|
||||
2BtSYR+OYLHNnCU5iDlaI5Z207f0ErTpYWw/PlgCF0G7dMLa
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
2
plat/diameter/doc/single_host/CAGenerate/ca.db
Normal file
2
plat/diameter/doc/single_host/CAGenerate/ca.db
Normal file
@@ -0,0 +1,2 @@
|
||||
V 170618165451Z 00 unknown /DC=com/DC=example/CN=OCSP Signer for Test Certifying CA
|
||||
V 170618165451Z 01 unknown /DC=com/DC=example/mail=root@example.com/CN=localhost
|
||||
1
plat/diameter/doc/single_host/CAGenerate/ca.db.attr
Normal file
1
plat/diameter/doc/single_host/CAGenerate/ca.db.attr
Normal file
@@ -0,0 +1 @@
|
||||
unique_subject = yes
|
||||
1
plat/diameter/doc/single_host/CAGenerate/ca.db.attr.old
Normal file
1
plat/diameter/doc/single_host/CAGenerate/ca.db.attr.old
Normal file
@@ -0,0 +1 @@
|
||||
unique_subject = yes
|
||||
1
plat/diameter/doc/single_host/CAGenerate/ca.db.old
Normal file
1
plat/diameter/doc/single_host/CAGenerate/ca.db.old
Normal file
@@ -0,0 +1 @@
|
||||
V 170618165451Z 00 unknown /DC=com/DC=example/CN=OCSP Signer for Test Certifying CA
|
||||
1
plat/diameter/doc/single_host/CAGenerate/ca.srl
Normal file
1
plat/diameter/doc/single_host/CAGenerate/ca.srl
Normal file
@@ -0,0 +1 @@
|
||||
02
|
||||
1
plat/diameter/doc/single_host/CAGenerate/ca.srl.old
Normal file
1
plat/diameter/doc/single_host/CAGenerate/ca.srl.old
Normal file
@@ -0,0 +1 @@
|
||||
01
|
||||
BIN
plat/diameter/doc/single_host/CAGenerate/fdTestExt
Normal file
BIN
plat/diameter/doc/single_host/CAGenerate/fdTestExt
Normal file
Binary file not shown.
16
plat/diameter/doc/single_host/CAGenerate/freeDiameter-1.conf
Normal file
16
plat/diameter/doc/single_host/CAGenerate/freeDiameter-1.conf
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
# -------- Test configuration ---------
|
||||
|
||||
Identity = "peer1.localdomain";
|
||||
Realm = "localdomain";
|
||||
# Port = 3868;
|
||||
# SecPort = 3869;
|
||||
|
||||
TLS_Cred = "./ca.crt",
|
||||
"./ca.key";
|
||||
TLS_CA = "./ca.pem";
|
||||
|
||||
#LoadExtension = "extensions/test_app.fdx" : "test_app1.conf";
|
||||
|
||||
ConnectPeer = "peer2.localdomain" { ConnectTo = "127.0.0.1"; No_TLS; port = 30868; };
|
||||
|
||||
152
plat/diameter/doc/single_host/CAGenerate/localhost.crt
Normal file
152
plat/diameter/doc/single_host/CAGenerate/localhost.crt
Normal file
@@ -0,0 +1,152 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 1 (0x1)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: DC=com, DC=example, CN=Test Certifying CA
|
||||
Validity
|
||||
Not Before: Jun 18 16:54:51 2016 GMT
|
||||
Not After : Jun 18 16:54:51 2017 GMT
|
||||
Subject: DC=com, DC=example/mail=root@example.com, CN=localhost
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:b7:cf:a3:84:a5:55:ae:d8:6f:a6:e9:4f:33:2c:
|
||||
b1:b6:5f:b2:b2:ac:e8:dc:ee:94:ba:55:15:ff:06:
|
||||
63:1b:48:c4:24:c1:d0:44:86:1b:52:a4:75:25:97:
|
||||
67:30:e2:6e:6f:13:f9:6c:ac:58:d7:55:1c:71:48:
|
||||
12:d6:06:1f:b5:1e:98:10:2a:73:74:19:5b:a0:22:
|
||||
9f:28:96:06:b1:e0:8a:40:ee:2d:2a:ab:01:2a:8d:
|
||||
d7:96:c6:1f:a3:d4:2c:af:fb:31:f4:a3:26:c8:39:
|
||||
d6:ee:fa:1f:06:b4:35:82:6e:5e:de:79:89:38:c9:
|
||||
02:7f:a9:56:cb:be:24:fd:c2:d5:6a:86:6b:d9:4e:
|
||||
90:08:01:e1:32:80:dc:2d:ae:40:9e:da:ad:ba:69:
|
||||
ea:31:e2:94:f1:1b:41:07:f1:fa:a8:a6:6e:b9:03:
|
||||
1f:1a:3e:64:18:4f:20:79:0f:49:de:df:f9:5a:b2:
|
||||
52:ad:72:9b:29:39:13:f1:0f:5f:cd:e2:a1:ef:54:
|
||||
1d:2b:63:d0:09:f1:08:c3:a8:0e:e1:46:be:29:d9:
|
||||
7e:93:06:da:98:4f:f6:49:f4:31:9d:2c:29:35:36:
|
||||
51:65:98:84:b7:87:03:ea:ba:61:94:ba:f3:00:17:
|
||||
43:10:9d:18:c6:58:7f:73:ff:6b:36:7c:ed:f4:66:
|
||||
ef:15
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Certificate Policies:
|
||||
Policy: X509v3 Any Policy
|
||||
|
||||
X509v3 Subject Key Identifier:
|
||||
B8:31:DB:64:96:F7:F9:88:99:4B:A3:D3:D9:98:2F:06:AF:AB:84:A7
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:5B:09:09:8C:18:28:52:5C:5B:39:E9:07:62:07:54:43:73:81:F1:33
|
||||
DirName:/DC=com/DC=example/CN=Test Certifying CA
|
||||
serial:EF:6F:E3:58:AA:53:DD:8F
|
||||
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
Netscape Comment:
|
||||
Testing Certificate for localhost
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
24:a1:20:db:9b:c2:87:81:84:64:d7:ce:de:81:29:63:63:19:
|
||||
2b:b9:21:4f:c1:82:79:02:fa:c4:b4:2e:5e:2c:cb:a4:86:f6:
|
||||
4f:02:f9:cb:a5:bb:ad:00:58:fd:4a:0a:45:19:74:5e:d5:80:
|
||||
18:fd:96:0a:05:22:33:ae:8b:65:41:47:07:3a:5f:5b:ab:c1:
|
||||
8d:92:1d:22:b1:74:8a:d6:db:81:c8:8c:d1:d3:d3:52:36:ec:
|
||||
a3:e4:64:c1:23:7c:0a:9c:36:ec:e4:cf:a2:f5:9b:1b:39:a4:
|
||||
94:0f:12:18:0a:f4:91:a1:71:89:13:c1:86:24:b5:46:d1:c9:
|
||||
de:8e:bc:c3:a9:90:c4:99:d3:99:36:de:47:10:89:b9:c7:e8:
|
||||
d4:2b:a4:65:3a:a9:9d:ea:d0:16:08:20:0c:c0:ec:b5:b1:2d:
|
||||
17:9e:45:32:ee:91:ee:9e:6f:59:03:2c:8f:dd:36:6d:d3:29:
|
||||
d0:4b:b0:f4:d5:76:dd:92:1b:89:d7:5b:e6:bb:90:61:0b:5f:
|
||||
55:84:f3:1c:cc:61:01:e5:3f:5c:08:0d:a5:41:51:00:6e:a8:
|
||||
e6:9b:f1:76:bd:f8:96:62:22:42:37:db:3e:29:a7:2c:70:2b:
|
||||
22:82:60:b8:9c:83:83:3c:d9:02:c7:0d:9f:b4:a6:a1:8f:81:
|
||||
76:41:48:53
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 1 (0x1)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: DC=com, DC=example, CN=Test Certifying CA
|
||||
Validity
|
||||
Not Before: Jun 18 16:54:51 2016 GMT
|
||||
Not After : Jun 18 16:54:51 2017 GMT
|
||||
Subject: DC=com, DC=example/mail=root@example.com, CN=localhost
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:b7:cf:a3:84:a5:55:ae:d8:6f:a6:e9:4f:33:2c:
|
||||
b1:b6:5f:b2:b2:ac:e8:dc:ee:94:ba:55:15:ff:06:
|
||||
63:1b:48:c4:24:c1:d0:44:86:1b:52:a4:75:25:97:
|
||||
67:30:e2:6e:6f:13:f9:6c:ac:58:d7:55:1c:71:48:
|
||||
12:d6:06:1f:b5:1e:98:10:2a:73:74:19:5b:a0:22:
|
||||
9f:28:96:06:b1:e0:8a:40:ee:2d:2a:ab:01:2a:8d:
|
||||
d7:96:c6:1f:a3:d4:2c:af:fb:31:f4:a3:26:c8:39:
|
||||
d6:ee:fa:1f:06:b4:35:82:6e:5e:de:79:89:38:c9:
|
||||
02:7f:a9:56:cb:be:24:fd:c2:d5:6a:86:6b:d9:4e:
|
||||
90:08:01:e1:32:80:dc:2d:ae:40:9e:da:ad:ba:69:
|
||||
ea:31:e2:94:f1:1b:41:07:f1:fa:a8:a6:6e:b9:03:
|
||||
1f:1a:3e:64:18:4f:20:79:0f:49:de:df:f9:5a:b2:
|
||||
52:ad:72:9b:29:39:13:f1:0f:5f:cd:e2:a1:ef:54:
|
||||
1d:2b:63:d0:09:f1:08:c3:a8:0e:e1:46:be:29:d9:
|
||||
7e:93:06:da:98:4f:f6:49:f4:31:9d:2c:29:35:36:
|
||||
51:65:98:84:b7:87:03:ea:ba:61:94:ba:f3:00:17:
|
||||
43:10:9d:18:c6:58:7f:73:ff:6b:36:7c:ed:f4:66:
|
||||
ef:15
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Certificate Policies:
|
||||
Policy: X509v3 Any Policy
|
||||
|
||||
X509v3 Subject Key Identifier:
|
||||
B8:31:DB:64:96:F7:F9:88:99:4B:A3:D3:D9:98:2F:06:AF:AB:84:A7
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:5B:09:09:8C:18:28:52:5C:5B:39:E9:07:62:07:54:43:73:81:F1:33
|
||||
DirName:/DC=com/DC=example/CN=Test Certifying CA
|
||||
serial:EF:6F:E3:58:AA:53:DD:8F
|
||||
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
Netscape Comment:
|
||||
Testing Certificate for localhost
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
24:a1:20:db:9b:c2:87:81:84:64:d7:ce:de:81:29:63:63:19:
|
||||
2b:b9:21:4f:c1:82:79:02:fa:c4:b4:2e:5e:2c:cb:a4:86:f6:
|
||||
4f:02:f9:cb:a5:bb:ad:00:58:fd:4a:0a:45:19:74:5e:d5:80:
|
||||
18:fd:96:0a:05:22:33:ae:8b:65:41:47:07:3a:5f:5b:ab:c1:
|
||||
8d:92:1d:22:b1:74:8a:d6:db:81:c8:8c:d1:d3:d3:52:36:ec:
|
||||
a3:e4:64:c1:23:7c:0a:9c:36:ec:e4:cf:a2:f5:9b:1b:39:a4:
|
||||
94:0f:12:18:0a:f4:91:a1:71:89:13:c1:86:24:b5:46:d1:c9:
|
||||
de:8e:bc:c3:a9:90:c4:99:d3:99:36:de:47:10:89:b9:c7:e8:
|
||||
d4:2b:a4:65:3a:a9:9d:ea:d0:16:08:20:0c:c0:ec:b5:b1:2d:
|
||||
17:9e:45:32:ee:91:ee:9e:6f:59:03:2c:8f:dd:36:6d:d3:29:
|
||||
d0:4b:b0:f4:d5:76:dd:92:1b:89:d7:5b:e6:bb:90:61:0b:5f:
|
||||
55:84:f3:1c:cc:61:01:e5:3f:5c:08:0d:a5:41:51:00:6e:a8:
|
||||
e6:9b:f1:76:bd:f8:96:62:22:42:37:db:3e:29:a7:2c:70:2b:
|
||||
22:82:60:b8:9c:83:83:3c:d9:02:c7:0d:9f:b4:a6:a1:8f:81:
|
||||
76:41:48:53
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEGjCCAwKgAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMRMwEQYKCZImiZPyLGQB
|
||||
GRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEbMBkGA1UEAxMSVGVzdCBD
|
||||
ZXJ0aWZ5aW5nIENBMB4XDTE2MDYxODE2NTQ1MVoXDTE3MDYxODE2NTQ1MVowZDET
|
||||
MBEGCgmSJomT8ixkARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxIDAe
|
||||
BgoJkiaJk/IsZAEDFBByb290QGV4YW1wbGUuY29tMRIwEAYDVQQDEwlsb2NhbGhv
|
||||
c3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3z6OEpVWu2G+m6U8z
|
||||
LLG2X7KyrOjc7pS6VRX/BmMbSMQkwdBEhhtSpHUll2cw4m5vE/lsrFjXVRxxSBLW
|
||||
Bh+1HpgQKnN0GVugIp8olgax4IpA7i0qqwEqjdeWxh+j1Cyv+zH0oybIOdbu+h8G
|
||||
tDWCbl7eeYk4yQJ/qVbLviT9wtVqhmvZTpAIAeEygNwtrkCe2q26aeox4pTxG0EH
|
||||
8fqopm65Ax8aPmQYTyB5D0ne3/laslKtcpspORPxD1/N4qHvVB0rY9AJ8QjDqA7h
|
||||
Rr4p2X6TBtqYT/ZJ9DGdLCk1NlFlmIS3hwPqumGUuvMAF0MQnRjGWH9z/2s2fO30
|
||||
Zu8VAgMBAAGjge8wgewwEQYDVR0gBAowCDAGBgRVHSAAMB0GA1UdDgQWBBS4Mdtk
|
||||
lvf5iJlLo9PZmC8Gr6uEpzB7BgNVHSMEdDBygBRbCQmMGChSXFs56QdiB1RDc4Hx
|
||||
M6FPpE0wSzETMBEGCgmSJomT8ixkARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4
|
||||
YW1wbGUxGzAZBgNVBAMTElRlc3QgQ2VydGlmeWluZyBDQYIJAO9v41iqU92PMAkG
|
||||
A1UdEwQCMAAwMAYJYIZIAYb4QgENBCMWIVRlc3RpbmcgQ2VydGlmaWNhdGUgZm9y
|
||||
IGxvY2FsaG9zdDANBgkqhkiG9w0BAQUFAAOCAQEAJKEg25vCh4GEZNfO3oEpY2MZ
|
||||
K7khT8GCeQL6xLQuXizLpIb2TwL5y6W7rQBY/UoKRRl0XtWAGP2WCgUiM66LZUFH
|
||||
BzpfW6vBjZIdIrF0itbbgciM0dPTUjbso+RkwSN8Cpw27OTPovWbGzmklA8SGAr0
|
||||
kaFxiRPBhiS1RtHJ3o68w6mQxJnTmTbeRxCJucfo1CukZTqpnerQFgggDMDstbEt
|
||||
F55FMu6R7p5vWQMsj902bdMp0Euw9NV23ZIbiddb5ruQYQtfVYTzHMxhAeU/XAgN
|
||||
pUFRAG6o5pvxdr34lmIiQjfbPimnLHArIoJguJyDgzzZAscNn7SmoY+BdkFIUw==
|
||||
-----END CERTIFICATE-----
|
||||
17
plat/diameter/doc/single_host/CAGenerate/localhost.csr
Normal file
17
plat/diameter/doc/single_host/CAGenerate/localhost.csr
Normal file
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICqTCCAZECAQAwZDETMBEGCgmSJomT8ixkARkWA2NvbTEXMBUGCgmSJomT8ixk
|
||||
ARkWB2V4YW1wbGUxIDAeBgoJkiaJk/IsZAEDFBByb290QGV4YW1wbGUuY29tMRIw
|
||||
EAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
||||
AQC3z6OEpVWu2G+m6U8zLLG2X7KyrOjc7pS6VRX/BmMbSMQkwdBEhhtSpHUll2cw
|
||||
4m5vE/lsrFjXVRxxSBLWBh+1HpgQKnN0GVugIp8olgax4IpA7i0qqwEqjdeWxh+j
|
||||
1Cyv+zH0oybIOdbu+h8GtDWCbl7eeYk4yQJ/qVbLviT9wtVqhmvZTpAIAeEygNwt
|
||||
rkCe2q26aeox4pTxG0EH8fqopm65Ax8aPmQYTyB5D0ne3/laslKtcpspORPxD1/N
|
||||
4qHvVB0rY9AJ8QjDqA7hRr4p2X6TBtqYT/ZJ9DGdLCk1NlFlmIS3hwPqumGUuvMA
|
||||
F0MQnRjGWH9z/2s2fO30Zu8VAgMBAAGgADANBgkqhkiG9w0BAQUFAAOCAQEACe/8
|
||||
eLWyhbHx6YZzliLGQsOZDqZrV+7rLCD7eYOt09DcxfHGqWuXYJfL6LCTAEkZtd2Z
|
||||
BYWVxmqNqeWvqlZUq7EMsYsAtAnQEnGE7mBoY0dEMMiRuirYmOblt1y1k3paDAY7
|
||||
HBt3hGiCxwZq8hlUQDmyB19GyoAogyaneqCWyMObisBeyFEjoYssXD+0KKGcZ/kt
|
||||
qKNK+8S/X2HBBB76chO0gJ3cTOpDVi5YjHOOk3Ovx4D2igN1C7xysecvXIrLVSj/
|
||||
9xSpzK0i1W5gWn1c6P5y4kxF/prmfwrJB8LyqP7x7VLqhlwDA6bkk17D4y/ogQM+
|
||||
0dIWUwwfxJdiEdjL4w==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
159
plat/diameter/doc/single_host/CAGenerate/ocsp.crt
Normal file
159
plat/diameter/doc/single_host/CAGenerate/ocsp.crt
Normal file
@@ -0,0 +1,159 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 0 (0x0)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: DC=com, DC=example, CN=Test Certifying CA
|
||||
Validity
|
||||
Not Before: Jun 18 16:54:51 2016 GMT
|
||||
Not After : Jun 18 16:54:51 2017 GMT
|
||||
Subject: DC=com, DC=example, CN=OCSP Signer for Test Certifying CA
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:b3:36:dc:c6:0e:a5:f3:e1:2f:0e:9c:94:19:10:
|
||||
00:fb:40:2b:6f:d0:1c:c6:de:64:32:fd:ac:d0:45:
|
||||
55:38:d8:77:11:46:8f:22:1f:93:c3:e9:fd:64:c8:
|
||||
1d:8d:21:65:8e:83:ae:91:53:bc:b9:a3:4d:b2:0e:
|
||||
ef:16:f8:52:9f:7b:69:dc:9c:73:cb:06:66:27:23:
|
||||
8d:6f:ba:11:e4:d6:0d:6f:25:9c:8e:d3:d8:1a:d5:
|
||||
2f:9d:00:06:b9:47:0c:24:00:87:e2:77:46:d0:6e:
|
||||
57:cd:f8:47:6e:50:cb:e7:71:d1:c5:50:bb:a5:2a:
|
||||
15:be:b4:cb:ea:d7:03:12:1b:d3:67:3c:76:12:df:
|
||||
e0:01:0d:69:36:16:1b:93:99:db:c2:5d:68:a4:f3:
|
||||
1f:56:24:4d:0c:da:1f:e4:81:04:bd:2c:d2:ec:8b:
|
||||
05:ff:eb:fb:2c:f9:92:93:e0:99:11:fa:64:aa:6b:
|
||||
83:ce:34:20:59:4b:b2:fa:d7:f7:6a:cd:b1:9d:90:
|
||||
56:43:ae:f2:ab:2e:e3:66:84:15:f5:ad:aa:6e:ce:
|
||||
c5:f5:3b:7b:bc:83:0c:7f:8f:f6:95:2c:b8:71:1a:
|
||||
d3:34:39:07:2e:2c:76:1c:6a:01:f2:1b:dd:59:ab:
|
||||
8c:4b:c9:bf:a7:54:bf:d4:3a:9f:13:fe:3d:7f:77:
|
||||
ce:89
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Key Identifier:
|
||||
30:46:BF:06:40:30:42:09:BE:75:D8:AC:C3:AC:7B:D3:4C:92:75:71
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:5B:09:09:8C:18:28:52:5C:5B:39:E9:07:62:07:54:43:73:81:F1:33
|
||||
DirName:/DC=com/DC=example/CN=Test Certifying CA
|
||||
serial:EF:6F:E3:58:AA:53:DD:8F
|
||||
|
||||
X509v3 Key Usage:
|
||||
Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment, Key Agreement, Certificate Sign, CRL Sign
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
X509v3 Extended Key Usage:
|
||||
OCSP Signing
|
||||
Netscape Comment:
|
||||
Testing OCSP Certificate
|
||||
OCSP No Check:
|
||||
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
e0:4d:17:4c:a4:ff:57:a1:db:d5:d2:77:7a:2d:70:51:8b:11:
|
||||
96:31:9f:fd:7e:d5:a7:a0:bb:d4:0d:ab:c2:5e:56:70:aa:84:
|
||||
47:f4:e9:28:51:c9:62:ca:3b:ad:5c:da:8c:60:37:72:d9:06:
|
||||
27:a1:60:cc:58:33:de:f1:85:3b:72:28:57:61:d6:8f:ce:46:
|
||||
84:53:bb:ad:61:2c:b8:c0:c0:db:88:9d:1c:a4:09:b8:8c:ca:
|
||||
49:d1:13:32:4b:b0:10:e9:65:b3:0b:68:30:65:e6:a0:6f:db:
|
||||
7c:ce:7b:52:c0:eb:7a:11:50:eb:2f:0e:2f:36:83:95:15:09:
|
||||
5f:f2:f8:2c:7d:a8:b2:c1:5e:f5:61:72:b7:a8:38:de:22:b7:
|
||||
a7:1c:43:03:c5:d4:01:ef:f0:fd:4e:9c:28:c7:b2:29:89:23:
|
||||
ff:c4:75:28:d2:c3:d8:e1:68:b1:08:9f:af:60:60:2a:ed:a0:
|
||||
96:b1:6c:f4:cc:61:bb:9d:af:5b:69:1f:3d:81:6c:ba:e2:e2:
|
||||
d6:38:aa:77:6b:a6:3f:e0:8a:8d:55:6d:df:06:cb:5b:1d:53:
|
||||
f7:96:4f:6f:98:8b:b3:0c:c3:2b:52:51:99:2d:09:fa:d0:a7:
|
||||
d5:1f:be:8b:43:21:0c:60:e0:bc:e3:42:f1:8a:d3:85:d1:cb:
|
||||
02:58:5a:98
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 0 (0x0)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: DC=com, DC=example, CN=Test Certifying CA
|
||||
Validity
|
||||
Not Before: Jun 18 16:54:51 2016 GMT
|
||||
Not After : Jun 18 16:54:51 2017 GMT
|
||||
Subject: DC=com, DC=example, CN=OCSP Signer for Test Certifying CA
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:b3:36:dc:c6:0e:a5:f3:e1:2f:0e:9c:94:19:10:
|
||||
00:fb:40:2b:6f:d0:1c:c6:de:64:32:fd:ac:d0:45:
|
||||
55:38:d8:77:11:46:8f:22:1f:93:c3:e9:fd:64:c8:
|
||||
1d:8d:21:65:8e:83:ae:91:53:bc:b9:a3:4d:b2:0e:
|
||||
ef:16:f8:52:9f:7b:69:dc:9c:73:cb:06:66:27:23:
|
||||
8d:6f:ba:11:e4:d6:0d:6f:25:9c:8e:d3:d8:1a:d5:
|
||||
2f:9d:00:06:b9:47:0c:24:00:87:e2:77:46:d0:6e:
|
||||
57:cd:f8:47:6e:50:cb:e7:71:d1:c5:50:bb:a5:2a:
|
||||
15:be:b4:cb:ea:d7:03:12:1b:d3:67:3c:76:12:df:
|
||||
e0:01:0d:69:36:16:1b:93:99:db:c2:5d:68:a4:f3:
|
||||
1f:56:24:4d:0c:da:1f:e4:81:04:bd:2c:d2:ec:8b:
|
||||
05:ff:eb:fb:2c:f9:92:93:e0:99:11:fa:64:aa:6b:
|
||||
83:ce:34:20:59:4b:b2:fa:d7:f7:6a:cd:b1:9d:90:
|
||||
56:43:ae:f2:ab:2e:e3:66:84:15:f5:ad:aa:6e:ce:
|
||||
c5:f5:3b:7b:bc:83:0c:7f:8f:f6:95:2c:b8:71:1a:
|
||||
d3:34:39:07:2e:2c:76:1c:6a:01:f2:1b:dd:59:ab:
|
||||
8c:4b:c9:bf:a7:54:bf:d4:3a:9f:13:fe:3d:7f:77:
|
||||
ce:89
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Subject Key Identifier:
|
||||
30:46:BF:06:40:30:42:09:BE:75:D8:AC:C3:AC:7B:D3:4C:92:75:71
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:5B:09:09:8C:18:28:52:5C:5B:39:E9:07:62:07:54:43:73:81:F1:33
|
||||
DirName:/DC=com/DC=example/CN=Test Certifying CA
|
||||
serial:EF:6F:E3:58:AA:53:DD:8F
|
||||
|
||||
X509v3 Key Usage:
|
||||
Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment, Key Agreement, Certificate Sign, CRL Sign
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
X509v3 Extended Key Usage:
|
||||
OCSP Signing
|
||||
Netscape Comment:
|
||||
Testing OCSP Certificate
|
||||
OCSP No Check:
|
||||
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
e0:4d:17:4c:a4:ff:57:a1:db:d5:d2:77:7a:2d:70:51:8b:11:
|
||||
96:31:9f:fd:7e:d5:a7:a0:bb:d4:0d:ab:c2:5e:56:70:aa:84:
|
||||
47:f4:e9:28:51:c9:62:ca:3b:ad:5c:da:8c:60:37:72:d9:06:
|
||||
27:a1:60:cc:58:33:de:f1:85:3b:72:28:57:61:d6:8f:ce:46:
|
||||
84:53:bb:ad:61:2c:b8:c0:c0:db:88:9d:1c:a4:09:b8:8c:ca:
|
||||
49:d1:13:32:4b:b0:10:e9:65:b3:0b:68:30:65:e6:a0:6f:db:
|
||||
7c:ce:7b:52:c0:eb:7a:11:50:eb:2f:0e:2f:36:83:95:15:09:
|
||||
5f:f2:f8:2c:7d:a8:b2:c1:5e:f5:61:72:b7:a8:38:de:22:b7:
|
||||
a7:1c:43:03:c5:d4:01:ef:f0:fd:4e:9c:28:c7:b2:29:89:23:
|
||||
ff:c4:75:28:d2:c3:d8:e1:68:b1:08:9f:af:60:60:2a:ed:a0:
|
||||
96:b1:6c:f4:cc:61:bb:9d:af:5b:69:1f:3d:81:6c:ba:e2:e2:
|
||||
d6:38:aa:77:6b:a6:3f:e0:8a:8d:55:6d:df:06:cb:5b:1d:53:
|
||||
f7:96:4f:6f:98:8b:b3:0c:c3:2b:52:51:99:2d:09:fa:d0:a7:
|
||||
d5:1f:be:8b:43:21:0c:60:e0:bc:e3:42:f1:8a:d3:85:d1:cb:
|
||||
02:58:5a:98
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEKjCCAxKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBLMRMwEQYKCZImiZPyLGQB
|
||||
GRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEbMBkGA1UEAxMSVGVzdCBD
|
||||
ZXJ0aWZ5aW5nIENBMB4XDTE2MDYxODE2NTQ1MVoXDTE3MDYxODE2NTQ1MVowWzET
|
||||
MBEGCgmSJomT8ixkARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxKzAp
|
||||
BgNVBAMTIk9DU1AgU2lnbmVyIGZvciBUZXN0IENlcnRpZnlpbmcgQ0EwggEiMA0G
|
||||
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzNtzGDqXz4S8OnJQZEAD7QCtv0BzG
|
||||
3mQy/azQRVU42HcRRo8iH5PD6f1kyB2NIWWOg66RU7y5o02yDu8W+FKfe2ncnHPL
|
||||
BmYnI41vuhHk1g1vJZyO09ga1S+dAAa5RwwkAIfid0bQblfN+EduUMvncdHFULul
|
||||
KhW+tMvq1wMSG9NnPHYS3+ABDWk2FhuTmdvCXWik8x9WJE0M2h/kgQS9LNLsiwX/
|
||||
6/ss+ZKT4JkR+mSqa4PONCBZS7L61/dqzbGdkFZDrvKrLuNmhBX1rapuzsX1O3u8
|
||||
gwx/j/aVLLhxGtM0OQcuLHYcagHyG91Zq4xLyb+nVL/UOp8T/j1/d86JAgMBAAGj
|
||||
ggEHMIIBAzAdBgNVHQ4EFgQUMEa/BkAwQgm+ddisw6x700ySdXEwewYDVR0jBHQw
|
||||
coAUWwkJjBgoUlxbOekHYgdUQ3OB8TOhT6RNMEsxEzARBgoJkiaJk/IsZAEZFgNj
|
||||
b20xFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMRswGQYDVQQDExJUZXN0IENlcnRp
|
||||
ZnlpbmcgQ0GCCQDvb+NYqlPdjzALBgNVHQ8EBAMCAf4wCQYDVR0TBAIwADATBgNV
|
||||
HSUEDDAKBggrBgEFBQcDCTAnBglghkgBhvhCAQ0EGhYYVGVzdGluZyBPQ1NQIENl
|
||||
cnRpZmljYXRlMA8GCSsGAQUFBzABBQQCBQAwDQYJKoZIhvcNAQEFBQADggEBAOBN
|
||||
F0yk/1eh29XSd3otcFGLEZYxn/1+1aegu9QNq8JeVnCqhEf06ShRyWLKO61c2oxg
|
||||
N3LZBiehYMxYM97xhTtyKFdh1o/ORoRTu61hLLjAwNuInRykCbiMyknREzJLsBDp
|
||||
ZbMLaDBl5qBv23zOe1LA63oRUOsvDi82g5UVCV/y+Cx9qLLBXvVhcreoON4it6cc
|
||||
QwPF1AHv8P1OnCjHsimJI//EdSjSw9jhaLEIn69gYCrtoJaxbPTMYbudr1tpHz2B
|
||||
bLri4tY4qndrpj/gio1Vbd8Gy1sdU/eWT2+Yi7MMwytSUZktCfrQp9UfvotDIQxg
|
||||
4LzjQvGK04XRywJYWpg=
|
||||
-----END CERTIFICATE-----
|
||||
17
plat/diameter/doc/single_host/CAGenerate/ocsp.csr
Normal file
17
plat/diameter/doc/single_host/CAGenerate/ocsp.csr
Normal file
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICoDCCAYgCAQAwWzETMBEGCgmSJomT8ixkARkWA2NvbTEXMBUGCgmSJomT8ixk
|
||||
ARkWB2V4YW1wbGUxKzApBgNVBAMTIk9DU1AgU2lnbmVyIGZvciBUZXN0IENlcnRp
|
||||
ZnlpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzNtzGDqXz
|
||||
4S8OnJQZEAD7QCtv0BzG3mQy/azQRVU42HcRRo8iH5PD6f1kyB2NIWWOg66RU7y5
|
||||
o02yDu8W+FKfe2ncnHPLBmYnI41vuhHk1g1vJZyO09ga1S+dAAa5RwwkAIfid0bQ
|
||||
blfN+EduUMvncdHFULulKhW+tMvq1wMSG9NnPHYS3+ABDWk2FhuTmdvCXWik8x9W
|
||||
JE0M2h/kgQS9LNLsiwX/6/ss+ZKT4JkR+mSqa4PONCBZS7L61/dqzbGdkFZDrvKr
|
||||
LuNmhBX1rapuzsX1O3u8gwx/j/aVLLhxGtM0OQcuLHYcagHyG91Zq4xLyb+nVL/U
|
||||
Op8T/j1/d86JAgMBAAGgADANBgkqhkiG9w0BAQUFAAOCAQEArFHItPRlHAT2Bfgk
|
||||
5eerQ0NJYRmo6Rz5R57rGjf92eZfH855KUy43tPdc+EFtp+RgBumpQi7RpeZyqmZ
|
||||
wtwQIev66I+Ls9/hXE8+VxtBlFAl99gFyzj5kRdfkjb0uOxWN6MSfxPcNE4J7oWm
|
||||
f8PBeIIcUCZEmFGvo1G2hoPyD2xUNYpMw0+XAPIsuqnqS/eY7SbYs+vByt9jPzTx
|
||||
cOZ0jpXRfHrf2gsvcQSmO6MLRwKiF3P62BUMp+UcTRtpznxSpwl9GdQN5E0H4pQh
|
||||
4HUYPmFRSkwFa8FkJGorMTcsR8U2/NiVGZnJgRz2ElSxLL4epBT7M/+MvURgH0Py
|
||||
4/ab4Q==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
545
plat/diameter/doc/single_host/CAGenerate/ssl_make_certs.sh
Normal file
545
plat/diameter/doc/single_host/CAGenerate/ssl_make_certs.sh
Normal file
@@ -0,0 +1,545 @@
|
||||
#!/bin/bash -e
|
||||
#
|
||||
# Generate a root CA cert for signing, and then a subject cert.
|
||||
# Usage: make-certs.sh hostname [user[@domain]] [more ...]
|
||||
# For testing only, probably still has some bugs in it.
|
||||
#
|
||||
|
||||
DOMAIN=example.com
|
||||
DAYS=365
|
||||
KEYTYPE=RSA
|
||||
KEYSIZE=2048
|
||||
CURVE=prime256v1
|
||||
DIGEST=SHA1
|
||||
CRLHOURS=24
|
||||
CRLDAYS=
|
||||
|
||||
# Cleanup temporary files at exit.
|
||||
touch openssl.cnf
|
||||
newcertdir=`mktemp -d`
|
||||
cleanup() {
|
||||
test -f openssl.cnf && rm -f openssl.cnf
|
||||
test -f ca.txt && rm -f ca.txt
|
||||
test -f ocsp.txt && rm -f ocsp.txt
|
||||
test -n "$newcertdir" && rm -fr "$newcertdir"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# The first argument is either a common name value or a flag indicating that
|
||||
# we're doing something other than issuing a cert.
|
||||
commonname="$1"
|
||||
refresh_crl=false
|
||||
revoke_cert=false
|
||||
ocsp_serve=false
|
||||
if test "x$commonname" = "x-refresh-crl" ; then
|
||||
refresh_crl=true
|
||||
commonname="$1"
|
||||
fi
|
||||
if test "x$commonname" = "x-refresh_crl" ; then
|
||||
refresh_crl=true
|
||||
commonname="$1"
|
||||
fi
|
||||
if test "x$commonname" = "x-revoke" ; then
|
||||
revoke_cert=true
|
||||
shift
|
||||
commonname="$1"
|
||||
fi
|
||||
if test "x$commonname" = "x-ocsp" ; then
|
||||
ocsp_serve=true
|
||||
commonname="$1"
|
||||
fi
|
||||
if test "x$commonname" = x ; then
|
||||
echo Usage: `basename $0` 'commonname' user'[@domain]' '[more [...]]'
|
||||
echo Usage: `basename $0` -revoke 'commonname'
|
||||
echo Usage: `basename $0` -ocsp
|
||||
echo Usage: `basename $0` -refresh-crl
|
||||
echo More:
|
||||
echo -e \\tKey type: "[RSA|DSA|EC]"
|
||||
echo -e \\tElliptic curve: "[prime256v1|secp384r1|secp521r1]"
|
||||
echo -e \\tKey usage: "[sign|signing|encrypt|encryption|agree|agreement|all]"
|
||||
echo -e \\tAuthority Access Info OCSP responder: "ocsp:URI"
|
||||
echo -e \\tCRL distribution point: "crl:URI"
|
||||
echo -e \\tSubject Alternative Name:
|
||||
echo -e \\t\\tHostname: "*"
|
||||
echo -e \\t\\tIP address: w.x.y.z
|
||||
echo -e \\t\\tEmail address: "*@*.com/edu/net/org/local"
|
||||
echo -e \\t\\tKerberos principal name: "*@*.COM/EDU/NET/ORG/LOCAL"
|
||||
echo -e \\tExtended key usage:
|
||||
echo -e \\t\\t1....
|
||||
echo -e \\t\\t2....
|
||||
echo -e \\t\\tid-kp-server-auth \| tls-server
|
||||
echo -e \\t\\tid-kp-client-auth \| tls-client
|
||||
echo -e \\t\\tid-kp-email-protection \| email
|
||||
echo -e \\t\\tid-ms-kp-sc-logon \| id-ms-sc-logon
|
||||
echo -e \\t\\tid-pkinit-kp-client-auth \| id-pkinit-client
|
||||
echo -e \\t\\tid-pkinit-kp-kdc \| id-pkinit-kdc
|
||||
echo -e \\t\\tca \| CA
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Choose a user name part for email attributes.
|
||||
GIVENUSER=$2
|
||||
test x"$GIVENUSER" = x && GIVENUSER=$USER
|
||||
echo "$GIVENUSER" | grep -q @ || GIVENUSER="$GIVENUSER"@$DOMAIN
|
||||
DOMAIN=`echo "$GIVENUSER" | cut -f2- -d@`
|
||||
|
||||
shift || true
|
||||
shift || true
|
||||
|
||||
# Done already?
|
||||
done=:
|
||||
|
||||
keygen() {
|
||||
case "$KEYTYPE" in
|
||||
DSA)
|
||||
openssl dsaparam $KEYSIZE -genkey
|
||||
;;
|
||||
EC)
|
||||
openssl ecparam -name $CURVE -noout -param_enc named_curve -genkey
|
||||
;;
|
||||
RSA|*)
|
||||
openssl genrsa $KEYSIZE -nodes
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Set some defaults.
|
||||
CA=FALSE
|
||||
if test -s ca.crldp.uri.txt ; then
|
||||
crlval="`cat ca.crldp.uri.txt`"
|
||||
crl="URI:$crlval"
|
||||
fi
|
||||
if test -s ca.ocsp.uri.txt ; then
|
||||
aiaval="`cat ca.ocsp.uri.txt`"
|
||||
aia="OCSP;URI:$aiaval"
|
||||
fi
|
||||
if test -s ca.domain.txt ; then
|
||||
domval="`cat ca.domain.txt`"
|
||||
if test -n "$domval" ; then
|
||||
DOMAIN="$domval"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Parse the arguments which indicate what sort of information we want.
|
||||
while test $# -gt 0 ; do
|
||||
type=
|
||||
value="$1"
|
||||
case "$value" in
|
||||
RSA|rsa)
|
||||
KEYTYPE=RSA
|
||||
;;
|
||||
DSA|dsa)
|
||||
KEYTYPE=DSA
|
||||
;;
|
||||
EC|ec)
|
||||
KEYTYPE=EC
|
||||
;;
|
||||
prime256v1|secp384r1|secp521r1)
|
||||
CURVE=$1
|
||||
;;
|
||||
OCSP:*|ocsp:*)
|
||||
aiaval=`echo "$value" | cut -f2- -d:`
|
||||
aia="OCSP;URI:$aiaval"
|
||||
;;
|
||||
CRL:*|crl:*)
|
||||
crlval=`echo "$value" | cut -f2- -d:`
|
||||
crl="URI:$crlval"
|
||||
;;
|
||||
signing|sign)
|
||||
keyusage="${keyusage:+${keyusage},}nonRepudiation,digitalSignature"
|
||||
;;
|
||||
encryption|encrypt)
|
||||
keyusage="${keyusage:+${keyusage},}keyEncipherment,dataEncipherment"
|
||||
;;
|
||||
agreement|agree)
|
||||
keyusage="${keyusage:+${keyusage},}keyAgreement"
|
||||
;;
|
||||
all)
|
||||
keyusage="digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign,encipherOnly,decipherOnly"
|
||||
;;
|
||||
ca|CA)
|
||||
CA=TRUE
|
||||
keyusage="${keyusage:+${keyusage},}nonRepudiation,digitalSignature,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign"
|
||||
;;
|
||||
1.*|2.*|id-*|tls-*|email|mail)
|
||||
ekuval=`echo "$value" | tr '[A-Z]' '[a-z]' | sed 's,\-,,g'`
|
||||
case "$ekuval" in
|
||||
idkpserverauth|tlsserver) ekuval=1.3.6.1.5.5.7.3.1;;
|
||||
idkpclientauth|tlsclient) ekuval=1.3.6.1.5.5.7.3.2;;
|
||||
idkpemailprotection|email|mail) ekuval=1.3.6.1.5.5.7.3.4;;
|
||||
idmskpsclogon|idmssclogon) ekuval=1.3.6.1.4.1.311.20.2.2;;
|
||||
idpkinitkpclientauth|idpkinitclient) ekuval=1.3.6.1.5.2.3.4;;
|
||||
idpkinitkpkdc|idpkinitkdc) ekuval=1.3.6.1.5.2.3.5;;
|
||||
esac
|
||||
if test -z "$eku" ; then
|
||||
eku="$ekuval"
|
||||
else
|
||||
eku="$eku,$ekuval"
|
||||
fi
|
||||
;;
|
||||
*@*.COM|*@*.EDU|*@*.NET|*@*.ORG|*@*.LOCAL)
|
||||
luser=`echo "$value" | tr '[A-Z]' '[a-z]'`
|
||||
if test "$luser" = "$value" ; then
|
||||
luser=
|
||||
fi
|
||||
type="otherName:1.3.6.1.5.2.2;SEQUENCE:$value,${luser:+otherName:1.3.6.1.4.1.311.20.2.3;UTF8:${luser},}otherName:1.3.6.1.4.1.311.20.2.3;UTF8"
|
||||
unset luser
|
||||
principals="$principals $value"
|
||||
;;
|
||||
*@*.com|*@*.edu|*@*.net|*@*.org|*@*.local) type=email;;
|
||||
[0-9]*.[0-9]*.[0-9]*.[0-9]*) type=IP;;
|
||||
*) type=DNS;;
|
||||
esac
|
||||
if test -n "$type" ; then
|
||||
newvalue="${type}:$value"
|
||||
if test -z "$altnames" ; then
|
||||
altnames="${newvalue}"
|
||||
else
|
||||
altnames="${altnames},${newvalue}"
|
||||
fi
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
# Build the configuration file, including bits on how to construct the CA
|
||||
# certificate, an OCSP responder certificate, and the issued certificate.
|
||||
cat > openssl.cnf <<- EOF
|
||||
[ca]
|
||||
default_ca = issuer
|
||||
|
||||
[issuer]
|
||||
private_key = `pwd`/ca.key
|
||||
certificate = `pwd`/ca.crt
|
||||
database = `pwd`/ca.db
|
||||
serial = `pwd`/ca.srl
|
||||
default_md = $DIGEST
|
||||
new_certs_dir = $newcertdir
|
||||
policy = no_policy
|
||||
|
||||
[no_policy]
|
||||
|
||||
[req_oids]
|
||||
domainComponent = 0.9.2342.19200300.100.1.25
|
||||
|
||||
[req_ca]
|
||||
prompt = no
|
||||
oid_section = req_oids
|
||||
distinguished_name = req_ca_name
|
||||
default_md = $DIGEST
|
||||
|
||||
[req_ca_name]
|
||||
EOF
|
||||
echo $DOMAIN | awk 'BEGIN {FS="."}{for(i=NF;i>0;i--){print NF-i ".domainComponent="$i;}}' >> openssl.cnf
|
||||
cat >> openssl.cnf <<- EOF
|
||||
commonName = Test Certifying CA
|
||||
|
||||
[v3_ca]
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid:always,issuer:always
|
||||
keyUsage=nonRepudiation,digitalSignature,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign
|
||||
basicConstraints=critical,CA:TRUE
|
||||
nsComment="Testing CA Certificate"
|
||||
EOF
|
||||
if test -n "$aia" ; then
|
||||
echo "authorityInfoAccess = ${aia}" >> openssl.cnf
|
||||
echo -n "$aiaval" > ca.ocsp.uri.txt
|
||||
fi
|
||||
if test -n "$crl" ; then
|
||||
echo "crlDistributionPoints = ${crl}" >> openssl.cnf
|
||||
echo -n "$crlval" > ca.crldp.uri.txt
|
||||
fi
|
||||
echo "$DOMAIN" > ca.domain.txt
|
||||
cat >> openssl.cnf <<- EOF
|
||||
|
||||
[req_ocsp]
|
||||
prompt = no
|
||||
oid_section = req_oids
|
||||
distinguished_name = req_ocsp_name
|
||||
default_md = $DIGEST
|
||||
|
||||
[req_ocsp_name]
|
||||
EOF
|
||||
echo $DOMAIN | awk 'BEGIN {FS="."}{for(i=NF;i>0;i--){print NF-i ".domainComponent="$i;}}' >> openssl.cnf
|
||||
cat >> openssl.cnf <<- EOF
|
||||
commonName = OCSP Signer for Test Certifying CA
|
||||
|
||||
[v3_ocsp]
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid:always,issuer:always
|
||||
keyUsage=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign
|
||||
basicConstraints=CA:FALSE
|
||||
extendedKeyUsage=1.3.6.1.5.5.7.3.9
|
||||
nsComment="Testing OCSP Certificate"
|
||||
1.3.6.1.5.5.7.48.1.5=ASN1:NULL
|
||||
EOF
|
||||
if test -n "$aia" ; then
|
||||
echo "authorityInfoAccess = ${aia}" >> openssl.cnf
|
||||
fi
|
||||
if test -n "$crl" ; then
|
||||
echo "crlDistributionPoints = ${crl}" >> openssl.cnf
|
||||
fi
|
||||
cat >> openssl.cnf <<- EOF
|
||||
|
||||
[req_issued]
|
||||
prompt = no
|
||||
oid_section = req_oids
|
||||
distinguished_name = req_issued_name
|
||||
default_md = $DIGEST
|
||||
|
||||
[req_issued_name]
|
||||
EOF
|
||||
echo $DOMAIN | awk 'BEGIN {FS="."}{for(i=NF;i>0;i--){print NF-i ".domainComponent="$i;}}' >> openssl.cnf
|
||||
cat >> openssl.cnf <<- EOF
|
||||
mail = $GIVENUSER
|
||||
commonName = $commonname
|
||||
|
||||
[v3_issued]
|
||||
certificatePolicies=2.5.29.32.0${eku:+,${eku}}
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid:always,issuer:always
|
||||
EOF
|
||||
if test -n "$aia" ; then
|
||||
echo "authorityInfoAccess = ${aia}" >> openssl.cnf
|
||||
fi
|
||||
if test -n "$crl" ; then
|
||||
echo "crlDistributionPoints = ${crl}" >> openssl.cnf
|
||||
fi
|
||||
if test -n "$keyusage" ; then
|
||||
echo "keyUsage = critical,${keyusage}" >> openssl.cnf
|
||||
fi
|
||||
if test -n "$altnames" ; then
|
||||
echo "subjectAltName = ${altnames}" >> openssl.cnf
|
||||
fi
|
||||
if test -n "$eku" ; then
|
||||
echo "extendedKeyUsage = ${eku}" >> openssl.cnf
|
||||
fi
|
||||
if test "x$CA" = xTRUE ; then
|
||||
echo "basicConstraints=critical,CA:TRUE" >> openssl.cnf
|
||||
echo 'nsComment="Testing CA Certificate for '"$commonname"'"' >> openssl.cnf
|
||||
else
|
||||
echo "basicConstraints=CA:FALSE" >> openssl.cnf
|
||||
echo 'nsComment="Testing Certificate for '"$commonname"'"' >> openssl.cnf
|
||||
fi
|
||||
for value in $principals; do
|
||||
user=`echo "$value" | cut -f1 -d@`
|
||||
realm=`echo "$value" | cut -f2- -d@`
|
||||
echo "" >> openssl.cnf
|
||||
echo "[$value]" >> openssl.cnf
|
||||
echo "realm=EXPLICIT:0,GeneralString:$realm" >> openssl.cnf
|
||||
echo "kerberosname=EXPLICIT:1,SEQUENCE:krb5$user" >> openssl.cnf
|
||||
|
||||
echo "" >> openssl.cnf
|
||||
echo "[krb5$user]" >> openssl.cnf
|
||||
echo "nametype=EXPLICIT:0,INTEGER:1" >> openssl.cnf
|
||||
echo "namelist=EXPLICIT:1,SEQUENCE:krb5basic$user" >> openssl.cnf
|
||||
|
||||
echo "[krb5basic$user]" >> openssl.cnf
|
||||
count=0
|
||||
for part in `echo "$user" | sed 's,/, ,g'` ; do
|
||||
echo "$count.part=GeneralString:$part" >> openssl.cnf
|
||||
count=`expr "$count" + 1`
|
||||
done
|
||||
done
|
||||
|
||||
# Create the data files for a new CA.
|
||||
if ! test -s ca.srl ; then
|
||||
(dd if=/dev/urandom bs=8 count=1 2> /dev/null) | od -t x1c | head -n 1 | awk '{$1="00";OFS="";print}' > ca.srl
|
||||
else
|
||||
echo "You already have a ca.srl file; not replacing."
|
||||
fi
|
||||
if ! test -s ca.db ; then
|
||||
touch ca.db
|
||||
else
|
||||
echo "You already have a ca.db file; not replacing."
|
||||
fi
|
||||
if ! test -s ca.db.attr ; then
|
||||
touch ca.db.attr
|
||||
else
|
||||
echo "You already have a ca.db.attr file; not replacing."
|
||||
fi
|
||||
|
||||
# If we need a CA key, generate one.
|
||||
if ! test -s ca.key ; then
|
||||
umask=`umask -p`
|
||||
umask 077
|
||||
keygen ca > ca.key 2> /dev/null
|
||||
$umask
|
||||
else
|
||||
echo "You already have a ca.key file; not replacing."
|
||||
done=echo
|
||||
fi
|
||||
|
||||
# If we need a CA certificate, generate one.
|
||||
if ! test -s ca.crt ; then
|
||||
sed -i -e 's,^\[req_ca\]$,\[req\],g' `pwd`/openssl.cnf
|
||||
openssl req -config `pwd`/openssl.cnf -new -key ca.key > ca.csr 2> /dev/null
|
||||
sed -i -e 's,^\[req\]$,\[req_ca\],g' `pwd`/openssl.cnf
|
||||
openssl x509 -extfile `pwd`/openssl.cnf -CAserial ca.srl -signkey ca.key -extensions v3_ca -req -in ca.csr -days $DAYS -out ca.crt ; : 2> /dev/null
|
||||
openssl x509 -noout -text -in ca.crt > ca.txt
|
||||
cat ca.crt >> ca.txt
|
||||
cat ca.txt > ca.crt
|
||||
rm ca.txt
|
||||
cat ca.crt > ca.chain.crt
|
||||
else
|
||||
echo "You already have a ca.crt file; not replacing."
|
||||
done=echo
|
||||
fi
|
||||
|
||||
# If we need an OCSP key, generate one.
|
||||
if ! test -s ocsp.key ; then
|
||||
umask=`umask -p`
|
||||
umask 077
|
||||
keygen ocsp > ocsp.key 2> /dev/null
|
||||
$umask
|
||||
else
|
||||
echo "You already have an ocsp.key file; not replacing."
|
||||
done=echo
|
||||
fi
|
||||
|
||||
# Generate the OCSP signing cert. Set the X.509v3 basic constraints and EKU.
|
||||
if ! test -s ocsp.crt ; then
|
||||
sed -i -e 's,^\[req_ocsp\]$,\[req\],g' `pwd`/openssl.cnf
|
||||
openssl req -config `pwd`/openssl.cnf -new -key ocsp.key > ocsp.csr 2> /dev/null
|
||||
sed -i -e 's,^\[req\]$,\[req_ocsp\],g' `pwd`/openssl.cnf
|
||||
openssl ca -batch -config `pwd`/openssl.cnf -extensions v3_ocsp -preserveDN -in ocsp.csr -days $DAYS -out ocsp.crt 2> /dev/null
|
||||
openssl x509 -noout -text -in ocsp.crt > ocsp.txt
|
||||
cat ocsp.crt >> ocsp.txt
|
||||
cat ocsp.txt > ocsp.crt
|
||||
rm ocsp.txt
|
||||
else
|
||||
echo "You already have an ocsp.crt file; not replacing."
|
||||
done=echo
|
||||
fi
|
||||
|
||||
# If we were told to revoke the certificate with the specified common name,
|
||||
# do so.
|
||||
if $revoke_cert ; then
|
||||
openssl ca -config `pwd`/openssl.cnf -revoke "$commonname".crt
|
||||
fi
|
||||
|
||||
# Always refresh the CRL.
|
||||
openssl ca -config `pwd`/openssl.cnf -gencrl ${CRLHOURS:+-crlhours ${CRLHOURS}} ${CRLDAYS:+-crldays ${CRLDAYS}} -out ca.crl.pem
|
||||
openssl crl -in ca.crl.pem -outform der -out ca.crl
|
||||
openssl crl -in ca.crl -inform der -noout -text > ca.crl.pem
|
||||
openssl crl -in ca.crl -inform der >> ca.crl.pem
|
||||
|
||||
# If we were told to start up the mini OCSP server, do so.
|
||||
if $ocsp_serve ; then
|
||||
openssl ocsp -text -index `pwd`/ca.db -CA `pwd`/ca.crt -rsigner `pwd`/ocsp.crt -rkey `pwd`/ocsp.key -rother `pwd`/ocsp.crt -port "`cut -f3 -d/ ca.ocsp.uri.txt | sed -r 's,(^[^:]*),0.0.0.0,g'`"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# If we're just here to do a revocation or refresh the CRL, we're done.
|
||||
if $revoke_cert || $refresh_crl ; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create a new serial number and whatnot if this is a new sub-CA.
|
||||
if test "x$CA" = xTRUE ; then
|
||||
if ! test -d "$commonname" ; then
|
||||
mkdir "$commonname"
|
||||
fi
|
||||
if ! test -s "$commonname/ca.srl" ; then
|
||||
(dd if=/dev/urandom bs=8 count=1 2> /dev/null) | od -t x1c | head -n 1 | awk '{$1="00";OFS="";print}' > "$commonname/ca.srl"
|
||||
else
|
||||
echo "You already have a $commonname/ca.srl file; not replacing."
|
||||
fi
|
||||
if test -n "$aia" ; then
|
||||
echo -n "$aiaval" > "$commonname/ca.ocsp.uri.txt"
|
||||
fi
|
||||
if test -n "$crl" ; then
|
||||
echo -n "$crlval" > "$commonname/ca.crldp.uri.txt"
|
||||
fi
|
||||
echo "$DOMAIN" > "$commonname/ca.domain.txt"
|
||||
touch "$commonname/ca.db" "$commonname/ca.db.attr"
|
||||
cert="$commonname/ca.crt"
|
||||
csr="$commonname/ca.csr"
|
||||
key="$commonname/ca.key"
|
||||
pem="$commonname/ca.pem"
|
||||
pfx="$commonname/ca.p12"
|
||||
ln -s ../`basename $0` "$commonname"/
|
||||
else
|
||||
cert="$commonname.crt"
|
||||
csr="$commonname.csr"
|
||||
key="$commonname.key"
|
||||
pem="$commonname.pem"
|
||||
pfx="$commonname.p12"
|
||||
fi
|
||||
|
||||
# Generate the subject's certificate. Set the X.509v3 basic constraints.
|
||||
if ! test -s "$cert" ; then
|
||||
# Generate another key, unless we have a key or CSR.
|
||||
if ! test -s "$key" && ! test -s "$csr" ; then
|
||||
umask=`umask -p`
|
||||
umask 077
|
||||
keygen "$commonname" > "$key" 2> /dev/null
|
||||
$umask
|
||||
else
|
||||
echo "You already have a $key or $csr file; not replacing."
|
||||
done=echo
|
||||
fi
|
||||
|
||||
if ! test -s "$csr" ; then
|
||||
sed -i -e 's,^\[req_issued\]$,\[req\],g' `pwd`/openssl.cnf
|
||||
openssl req -config `pwd`/openssl.cnf -new -key "$key" > "$csr" 2> /dev/null
|
||||
sed -i -e 's,^\[req\]$,\[req_issued\],g' `pwd`/openssl.cnf
|
||||
fi
|
||||
openssl ca -batch -config `pwd`/openssl.cnf -extensions v3_issued -preserveDN -in "$csr" -days $DAYS -out "$cert" 2> /dev/null
|
||||
openssl x509 -noout -text -in "$cert" > "$cert.txt"
|
||||
cat "$cert" >> "$cert.txt"
|
||||
cat "$cert.txt" > "$cert"
|
||||
rm -f "$cert.txt"
|
||||
else
|
||||
echo "You already have a $cert file; not replacing."
|
||||
done=echo
|
||||
fi
|
||||
|
||||
if test -s ca.chain.crt ; then
|
||||
chain=ca.chain.crt
|
||||
else
|
||||
chain=ca.crt
|
||||
fi
|
||||
if test "x$CA" = xTRUE ; then
|
||||
cat "$chain" "$cert" > "$commonname/ca.chain.crt"
|
||||
fi
|
||||
|
||||
# Create ca.pem and the subject's name.pem for the benefit of applications
|
||||
# which expect both the private key and the certificate in one file.
|
||||
umask=`umask -p`
|
||||
umask 077
|
||||
if ! test -s ca.pem ; then
|
||||
cat ca.key ca.crt > ca.pem
|
||||
else
|
||||
echo "You already have a ca.pem file; not replacing."
|
||||
done=echo
|
||||
fi
|
||||
if ! test -s "$pem" ; then
|
||||
cat "$key" "$cert" > "$pem"
|
||||
else
|
||||
echo "You already have a $pem file; not replacing."
|
||||
done=echo
|
||||
fi
|
||||
if ! test -s "$pfx" ; then
|
||||
openssl pkcs12 -export -inkey "$key" -in "$cert" -name "$commonname" -out "$pfx" -nodes -passout pass:
|
||||
else
|
||||
echo "You already have a $pfx file; not replacing."
|
||||
done=echo
|
||||
fi
|
||||
$umask
|
||||
$done
|
||||
|
||||
echo CA certificate:
|
||||
openssl x509 -noout -issuer -in ca.crt | sed s,=\ ,\ ,g
|
||||
openssl x509 -noout -subject -in ca.crt | sed s,=\ ,\ ,g
|
||||
echo
|
||||
echo End entity certificate:
|
||||
openssl x509 -noout -issuer -in "$cert" | sed s,=\ ,\ ,g
|
||||
openssl x509 -noout -subject -in "$cert" | sed s,=\ ,\ ,g
|
||||
openssl x509 -noout -serial -in "$cert" | sed s,=,\ ,g
|
||||
echo
|
||||
echo PKCS12 bag:
|
||||
openssl pkcs12 -in "$pfx" -nodes -nokeys -nocerts -info -passin pass:
|
||||
echo
|
||||
echo Verifying:
|
||||
echo + openssl verify -CAfile "$chain" "$cert"
|
||||
openssl verify -CAfile "$chain" "$cert"
|
||||
1
plat/diameter/doc/single_host/demoCA/index.txt.attr
Normal file
1
plat/diameter/doc/single_host/demoCA/index.txt.attr
Normal file
@@ -0,0 +1 @@
|
||||
unique_subject = yes
|
||||
1
plat/diameter/doc/single_host/demoCA/index.txt.attr.old
Normal file
1
plat/diameter/doc/single_host/demoCA/index.txt.attr.old
Normal file
@@ -0,0 +1 @@
|
||||
unique_subject = yes
|
||||
1
plat/diameter/doc/single_host/demoCA/index.txt.old
Normal file
1
plat/diameter/doc/single_host/demoCA/index.txt.old
Normal file
@@ -0,0 +1 @@
|
||||
V 170618170115Z 01 unknown /C=FR/ST=BdR/O=fD/OU=Tests/CN=peer1.localdomain
|
||||
1
plat/diameter/doc/single_host/demoCA/serial
Normal file
1
plat/diameter/doc/single_host/demoCA/serial
Normal file
@@ -0,0 +1 @@
|
||||
03
|
||||
1
plat/diameter/doc/single_host/demoCA/serial.old
Normal file
1
plat/diameter/doc/single_host/demoCA/serial.old
Normal file
@@ -0,0 +1 @@
|
||||
02
|
||||
BIN
plat/diameter/doc/single_host/fdTestExt
Normal file
BIN
plat/diameter/doc/single_host/fdTestExt
Normal file
Binary file not shown.
16
plat/diameter/doc/single_host/freeDiameter-1.conf
Normal file
16
plat/diameter/doc/single_host/freeDiameter-1.conf
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
# -------- Test configuration ---------
|
||||
|
||||
Identity = "peer1.localdomain";
|
||||
Realm = "localdomain";
|
||||
Port = 3868;
|
||||
SecPort = 3869;
|
||||
|
||||
TLS_Cred = "./cacert.pem",
|
||||
"./cakey.pem";
|
||||
TLS_CA = "./cacert.pem";
|
||||
|
||||
#LoadExtension = "extensions/test_app.fdx" : "test_app1.conf";
|
||||
|
||||
ConnectPeer = "peer2.localdomain" { ConnectTo = "127.0.0.1"; No_TLS; port = 30868; };
|
||||
|
||||
15
plat/diameter/doc/single_host/freeDiameter-2.conf
Normal file
15
plat/diameter/doc/single_host/freeDiameter-2.conf
Normal file
@@ -0,0 +1,15 @@
|
||||
# -------- Test configuration ---------
|
||||
|
||||
Identity = "peer2.localdomain";
|
||||
Realm = "localdomain";
|
||||
Port = 30868;
|
||||
SecPort = 30869;
|
||||
|
||||
TLS_Cred = "peer2.cert.pem",
|
||||
"peer2.key.pem";
|
||||
TLS_CA = "cacert.pem";
|
||||
|
||||
LoadExtension = "extensions/test_app.fdx" : "test_app2.conf";
|
||||
|
||||
ConnectPeer = "peer1.localdomain" { ConnectTo = "127.0.0.1"; No_TLS; };
|
||||
|
||||
20
plat/diameter/doc/single_host/make_certs.sh
Normal file
20
plat/diameter/doc/single_host/make_certs.sh
Normal file
@@ -0,0 +1,20 @@
|
||||
rm -rf demoCA
|
||||
mkdir demoCA
|
||||
echo 01 > demoCA/serial
|
||||
touch demoCA/index.txt
|
||||
|
||||
|
||||
|
||||
# CA self certificate
|
||||
openssl req -new -batch -x509 -days 3650 -nodes -newkey rsa:1024 -out cacert.pem -keyout cakey.pem -subj /CN=ca.localdomain/C=FR/ST=BdR/L=Aix/O=fD/OU=Tests
|
||||
|
||||
#peer1
|
||||
openssl genrsa -out peer1.key.pem 1024
|
||||
openssl req -new -batch -out peer1.csr.pem -key peer1.key.pem -subj /CN=peer1.localdomain/C=FR/ST=BdR/L=Aix/O=fD/OU=Tests
|
||||
openssl ca -cert cacert.pem -keyfile cakey.pem -in peer1.csr.pem -out peer1.cert.pem -outdir . -batch
|
||||
|
||||
#peer2
|
||||
openssl genrsa -out peer2.key.pem 1024
|
||||
openssl req -new -batch -out peer2.csr.pem -key peer2.key.pem -subj /CN=peer2.localdomain/C=FR/ST=BdR/L=Aix/O=fD/OU=Tests
|
||||
openssl ca -cert cacert.pem -keyfile cakey.pem -in peer2.csr.pem -out peer2.cert.pem -outdir . -batch
|
||||
|
||||
0
plat/diameter/doc/single_host/test_app1.conf
Normal file
0
plat/diameter/doc/single_host/test_app1.conf
Normal file
0
plat/diameter/doc/single_host/test_app2.conf
Normal file
0
plat/diameter/doc/single_host/test_app2.conf
Normal file
74
plat/diameter/doc/test_app.conf.sample
Normal file
74
plat/diameter/doc/test_app.conf.sample
Normal file
@@ -0,0 +1,74 @@
|
||||
#######################
|
||||
# This file contains the description of configuration and general information about the
|
||||
# "test_app" extension.
|
||||
|
||||
# This extension provides a simple way to send a predefined message over the Diameter Network.
|
||||
# It may be used to test the Routing or other base mechanisms from the Diameter network.
|
||||
|
||||
# In order to enable this extension, the main freeDiameter configuration file
|
||||
# must contain the following declaration:
|
||||
# LoadExtension = "extensions/app_test.fdx" : "/path/to/app_test.conf" ;
|
||||
# Note that the conffile may be omitted, in which case default parameters will be assumed.
|
||||
#######################
|
||||
|
||||
|
||||
#######################
|
||||
# Configuration of the test message
|
||||
|
||||
# This application is defined as a Vendor-Specific application.
|
||||
# Since freeDiameter does not have a IANA-assigned Vendor ID, we let a configurable value here:
|
||||
# vendor-id = 999999;
|
||||
|
||||
# The application id. Same remark as previously.
|
||||
# appli-id = 999999;
|
||||
|
||||
# The command code for Test-Request and Test-Answer. The range 0xfffffe-ffffff (dec: 16777215) is reserved for experimental use.
|
||||
# cmd-id = 16777214;
|
||||
|
||||
# The AVP id for the test.
|
||||
# avp-id = 345678;
|
||||
|
||||
# Another AVP id for long payload test. default to value 0, meaning this is not used.
|
||||
# long-avp-id = 0;
|
||||
|
||||
# Define the payload length of the long-avp. Default 5000 bytes.
|
||||
# long-avp-len = 5000;
|
||||
|
||||
|
||||
#######################
|
||||
# Configuration of the extension behavior
|
||||
|
||||
# The mode for the extension.
|
||||
# - server: Answer incoming requests. The signal is ignored.
|
||||
# - client: Send a request when the signal is received, and measure the time to receiving answer.
|
||||
# - both: acts as client and server
|
||||
# mode = both;
|
||||
|
||||
# The behavior can be changed by specifying additional "benchmark;" keyword.
|
||||
# When this keyword appears, it changes the behavior as follow:
|
||||
# - server is silent on message reception, only the activity summary is displayed every 30 seconds
|
||||
# - client attempts to send as many messages as possible during 10 seconds and counts them.
|
||||
# The benchmark keyword can be followed optionally by two integers:
|
||||
# duration is the time for the measurement, in seconds (default 10).
|
||||
# concurrency is the number of messages that can be on the wire before waiting for an answer (default 100).
|
||||
# benchmark [duration concurrency];
|
||||
|
||||
|
||||
#######################
|
||||
# Client-specific configuration
|
||||
|
||||
# The Destination-Realm for the message
|
||||
# (default is sending to same realm as local peer).
|
||||
# dest-realm = "foreign.net";
|
||||
|
||||
# The Destination-Host for the message.
|
||||
# (default is not providing this AVP).
|
||||
# dest-host = "server.foreign.net";
|
||||
|
||||
# The User-Name for the message (may be useful for some routing tests).
|
||||
# (default is not providing this AVP).
|
||||
# user-name = "user@server.foreign.net";
|
||||
|
||||
# The signal that triggers sending the test message
|
||||
# Note: Symbolic names are not recognized, you must use integers
|
||||
# signal = 10;
|
||||
59
plat/diameter/doc/test_netemul.conf.sample
Normal file
59
plat/diameter/doc/test_netemul.conf.sample
Normal file
@@ -0,0 +1,59 @@
|
||||
# This file contains information for configuring the test_netemul extension.
|
||||
# To find how to have freeDiameter load this extension, please refer to the freeDiameter documentation.
|
||||
#
|
||||
# The test_netemul extension implements a Diameter proxy that behaves like simple forwarding agent,
|
||||
# with the exception that it can introduce delay in the forwarding of the messages and generate duplicates
|
||||
# of messages, as can be expected from a real Diameter network. It can also generate routing errors when
|
||||
# connected to more than 2 peers.
|
||||
|
||||
|
||||
# LATENCY:
|
||||
# Two parameters are used to control the delay introduced in the messages.
|
||||
# - latency_average:
|
||||
# This is the average delay introduced in the packets.
|
||||
# Set to 0 to not add any latency (beyond the normal processing time).
|
||||
# The value is expressed as an integer followed by a unit which can
|
||||
# be 's' (seconds) or 'ms' (milliseconds). Example:
|
||||
# latency_average = 700 ms;
|
||||
#
|
||||
# - latency_deviation:
|
||||
# This parameter controls the variance in the latency. It is expressed
|
||||
# as a value between 0 % and 100 %. When set to 0 %, all messages will be delayed
|
||||
# by exactly latency_average. Otherwise, it represents the width of the interval
|
||||
# "around" the average where "most" of the latency will be chosen (the distribution
|
||||
# has a Gaussian shape). Example:
|
||||
# latency_deviation = 25 %;
|
||||
#
|
||||
# The default values give an added latency "mostly" between 0.4 and 0.6 seconds:
|
||||
# latency_average = 500 ms;
|
||||
# latency_deviation = 20 % ;
|
||||
|
||||
|
||||
# REORDERING:
|
||||
# There is no special control over the reordering of messages. It may simply happen
|
||||
# as a result of the latency. If you want to get a lot of reordering, set the
|
||||
# latency_variance to a high value.
|
||||
|
||||
|
||||
# DUPLICATES:
|
||||
# Duplicate messages are expected in the Diameter protocol by design, as a consequence
|
||||
# of the failover mechanism that provides the protocol's reliability.
|
||||
# - dupl_proba:
|
||||
# This value gives the probability of producing a duplicate of a forwarded message.
|
||||
# The value is comprized between 0 (no duplicates) and 1 (duplicate all messages).
|
||||
# Duplicates are created for requests, but may result in duplicate answers
|
||||
# received by your Diameter client(s), depending on your server(s)'s behavior.
|
||||
# In the case of freeDiameter client, the duplicate answer is automatically filtered out
|
||||
# because the hop-by-hop id has already been used.
|
||||
# Note that each duplicate copy is an independent message,
|
||||
# which receives a different latency, and might be routed to a different server if you
|
||||
# use for example load-balancing.
|
||||
# The parameter can take several forms:
|
||||
# dupl_proba = 0 ;
|
||||
# Disables the generation of duplicate messages completely.
|
||||
# dupl_proba = 1 / 10000 ;
|
||||
# dupl_proba = 0.0001 ;
|
||||
# Around 1 messages over ten thousands will be duplicated.
|
||||
#
|
||||
# Default value:
|
||||
# dupl_proba = 1 / 100 ;
|
||||
8
plat/diameter/doc/test_sip.conf.sample
Normal file
8
plat/diameter/doc/test_sip.conf.sample
Normal file
@@ -0,0 +1,8 @@
|
||||
#User configuration
|
||||
username = "awestfahl"
|
||||
password = "test"
|
||||
sip_aor = "sip:awestfahl@tera.ics.keio.ac.jp"
|
||||
|
||||
#Destination information
|
||||
destination_realm = "freediameter.net"
|
||||
destination_sip = "sip:awestfahl@freediameter.net"
|
||||
1559
plat/diameter/extensions/sh_app/dict_dcca.c
Normal file
1559
plat/diameter/extensions/sh_app/dict_dcca.c
Normal file
File diff suppressed because it is too large
Load Diff
859
plat/diameter/extensions/sh_app/dict_dcca_3gpp.c
Normal file
859
plat/diameter/extensions/sh_app/dict_dcca_3gpp.c
Normal file
@@ -0,0 +1,859 @@
|
||||
/*
|
||||
* Dictionary definitions of objects specified in DCCA (Nokia, 3GPP).
|
||||
*/
|
||||
#include "extension.h"
|
||||
|
||||
|
||||
/* The content of this file follows the same structure as dict_base_proto.c */
|
||||
|
||||
#define CHECK_dict_new( _type, _data, _parent, _ref ) \
|
||||
CHECK_FCT( fd_dict_new( fd_g_config->cnf_dict, (_type), (_data), (_parent), (_ref)) );
|
||||
|
||||
#define CHECK_dict_search( _type, _criteria, _what, _result ) \
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, (_type), (_criteria), (_what), (_result), ENOENT) );
|
||||
|
||||
struct local_rules_definition {
|
||||
char *avp_name;
|
||||
enum rule_position position;
|
||||
int min;
|
||||
int max;
|
||||
};
|
||||
|
||||
#define RULE_ORDER( _position ) ((((_position) == RULE_FIXED_HEAD) || ((_position) == RULE_FIXED_TAIL)) ? 1 : 0 )
|
||||
|
||||
#define PARSE_loc_rules( _rulearray, _parent) { \
|
||||
int __ar; \
|
||||
for (__ar=0; __ar < sizeof(_rulearray) / sizeof((_rulearray)[0]); __ar++) { \
|
||||
struct dict_rule_data __data = { NULL, \
|
||||
(_rulearray)[__ar].position, \
|
||||
0, \
|
||||
(_rulearray)[__ar].min, \
|
||||
(_rulearray)[__ar].max}; \
|
||||
__data.rule_order = RULE_ORDER(__data.rule_position); \
|
||||
CHECK_FCT( fd_dict_search( \
|
||||
fd_g_config->cnf_dict, \
|
||||
DICT_AVP, \
|
||||
AVP_BY_NAME, \
|
||||
(_rulearray)[__ar].avp_name, \
|
||||
&__data.rule_avp, 0 ) ); \
|
||||
if ( !__data.rule_avp ) { \
|
||||
TRACE_DEBUG(INFO, "AVP Not found: '%s'", (_rulearray)[__ar].avp_name ); \
|
||||
return ENOENT; \
|
||||
} \
|
||||
CHECK_FCT_DO( fd_dict_new( fd_g_config->cnf_dict, DICT_RULE, &__data, _parent, NULL), \
|
||||
{ \
|
||||
TRACE_DEBUG(INFO, "Error on rule with AVP '%s'", \
|
||||
(_rulearray)[__ar].avp_name ); \
|
||||
return EINVAL; \
|
||||
} ); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define enumval_def_u32( _val_, _str_ ) \
|
||||
{ _str_, { .u32 = _val_ }}
|
||||
|
||||
#define enumval_def_os( _len_, _val_, _str_ ) \
|
||||
{ _str_, { .os = { .data = (unsigned char *)_val_, .len = _len_ }}}
|
||||
|
||||
|
||||
int dict_dcca_3gpp_entry(char * conffile)
|
||||
{
|
||||
TRACE_ENTRY("%p", conffile);
|
||||
|
||||
#if 0
|
||||
/* Applications section */
|
||||
{
|
||||
/* Create the vendors */
|
||||
{
|
||||
struct dict_vendor_data vendor_data = { 10415, "3GPP" };
|
||||
CHECK_FCT(fd_dict_new(fd_g_config->cnf_dict, DICT_VENDOR, &vendor_data, NULL, NULL));
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* AVP section */
|
||||
{
|
||||
struct dict_object * Address_type;
|
||||
struct dict_object * UTF8String_type;
|
||||
struct dict_object * DiameterIdentity_type;
|
||||
struct dict_object * DiameterURI_type;
|
||||
struct dict_object * Time_type;
|
||||
|
||||
CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "Address", &Address_type);
|
||||
CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "UTF8String", &UTF8String_type);
|
||||
CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "DiameterIdentity", &DiameterIdentity_type);
|
||||
CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "DiameterURI", &DiameterURI_type);
|
||||
CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "Time", &Time_type);
|
||||
|
||||
/* Reporting-Reason */
|
||||
{
|
||||
/*
|
||||
Enumerated. Will be present if quota was
|
||||
exhausted for one or more metering types. Only
|
||||
one Reporting-Reason AVP can be present in the
|
||||
Used-Service-Unit AVP. (Note that the Reporting-
|
||||
Reason AVP may be present also at the MSCC
|
||||
level; see below.)
|
||||
The following values are supported:
|
||||
|
||||
QUOTA_EXHAUSTED(3); Quota for the
|
||||
associated metering type has been
|
||||
exhausted. With this reporting reason there is
|
||||
only one metering type in this Used-Service-
|
||||
Unit AVP.
|
||||
|
||||
OTHER_QUOTA_TYPE(5); Quota for one or
|
||||
more of the other metering types has been
|
||||
exhausted. With this reporting reason there
|
||||
may be multiple metering types in Used-
|
||||
Service-Unit AVP.
|
||||
|
||||
POOL_EXHAUSTED(8); Quota from the
|
||||
credit pool has been exhausted. This reporting
|
||||
reason is used if the quota for the associated
|
||||
metering type was granted from a credit pool
|
||||
by using the GSU-Pool-Reference AVP in the
|
||||
CCA. With this reporting reason there is only
|
||||
one metering type in the Used-Service-Unit
|
||||
AVP.
|
||||
*/
|
||||
|
||||
struct dict_object *type;
|
||||
struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Reporting-Reason)" , NULL, NULL, NULL };
|
||||
// struct dict_enumval_data t_1 = { "QHT", { .i32 = 1 }};
|
||||
// struct dict_enumval_data t_2 = { "FINAL", { .i32 = 2 }};
|
||||
struct dict_enumval_data t_3 = { "QUOTA_EXHAUSTED", { .i32 = 3 }};
|
||||
// struct dict_enumval_data t_4 = { "VALIDITY_TIME", { .i32 = 4 }};
|
||||
struct dict_enumval_data t_5 = { "OTHER_QUOTA_TYPE", { .i32 = 5 }};
|
||||
// struct dict_enumval_data t_6 = { "RATING_CONDITION_CHANGE", { .i32 = 6 }};
|
||||
// struct dict_enumval_data t_7 = { "FORCED_REAUTHORIZATION", { .i32 = 7 }};
|
||||
struct dict_enumval_data t_8 = { "POOL_EXHAUSTED", { .i32 = 8 }};
|
||||
|
||||
struct dict_avp_data data = {
|
||||
872, /* Code */
|
||||
10415, /* Vendor */
|
||||
"Reporting-Reason", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_INTEGER32 /* base type of data */
|
||||
};
|
||||
/* Create the Enumerated type, and then the AVP */
|
||||
CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
|
||||
CHECK_dict_new( DICT_ENUMVAL, &t_3 , type, NULL);
|
||||
CHECK_dict_new( DICT_ENUMVAL, &t_5 , type, NULL);
|
||||
CHECK_dict_new( DICT_ENUMVAL, &t_8 , type, NULL);
|
||||
CHECK_dict_new( DICT_AVP, &data , type, NULL);
|
||||
}
|
||||
|
||||
/* Trigger */
|
||||
{
|
||||
/*
|
||||
Grouped. The presence of the Trigger AVP in the
|
||||
CCR identifies the event(s) triggering the CCR.
|
||||
*/
|
||||
|
||||
struct dict_avp_data data = {
|
||||
1264, /* Code */
|
||||
10415, /* Vendor */
|
||||
"Trigger", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_GROUPED /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
|
||||
}
|
||||
|
||||
/* Trigger-Type */
|
||||
{
|
||||
/*
|
||||
Enumerated. One or more of these AVPs may be
|
||||
present. Indicates the event that triggered the
|
||||
MSCC. Supported values are:
|
||||
|
||||
CHANGE_IN_SGSN_IP_ADDRESS (1), a change in the SGSN address.
|
||||
|
||||
CHANGEINQOS_ANY (2), a change in the QoS profile
|
||||
|
||||
CHANGEINRAT (4), a change in radio access technology
|
||||
|
||||
*/
|
||||
|
||||
struct dict_object *type;
|
||||
struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Trigger-Type)" , NULL, NULL, NULL };
|
||||
struct dict_enumval_data t_1 = { "CHANGE_IN_SGSN_IP_ADDRESS", { .i32 = 1 }};
|
||||
struct dict_enumval_data t_2 = { "CHANGEINQOS_ANY", { .i32 = 2 }};
|
||||
struct dict_enumval_data t_4 = { "CHANGEINRAT", { .i32 = 4 }};
|
||||
|
||||
struct dict_avp_data data = {
|
||||
870, /* Code */
|
||||
10415, /* Vendor */
|
||||
"Trigger-Type", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_INTEGER32 /* base type of data */
|
||||
};
|
||||
/* Create the Enumerated type, and then the AVP */
|
||||
CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
|
||||
CHECK_dict_new( DICT_ENUMVAL, &t_1 , type, NULL);
|
||||
CHECK_dict_new( DICT_ENUMVAL, &t_2 , type, NULL);
|
||||
CHECK_dict_new( DICT_ENUMVAL, &t_4 , type, NULL);
|
||||
CHECK_dict_new( DICT_AVP, &data , type, NULL);
|
||||
}
|
||||
|
||||
/* Service-Information */
|
||||
{
|
||||
/*
|
||||
Grouped. The Service-Information purpose is to
|
||||
allow the transmission of additional 3GPP service
|
||||
specific information elements (3GPP 32.299
|
||||
Rel7).
|
||||
Service-Information :: = < AVP Header: 873>
|
||||
* [ Subscription-Id ]
|
||||
[ AoC-Information ]
|
||||
[ PS-Information ]
|
||||
[ WLAN-Information ]
|
||||
[ IMS-Information ]
|
||||
[ MMS-Information ]
|
||||
[ LCS-Information ]
|
||||
[ PoC-Information ]
|
||||
[ MBMS-Information ]
|
||||
[ SMS-Information ]
|
||||
[ MMTel-Information ]
|
||||
[ Service-Generic-Information ]
|
||||
[ IM-Information ]
|
||||
[ DCD-Information ]
|
||||
*/
|
||||
|
||||
struct dict_avp_data data = {
|
||||
873, /* Code */
|
||||
10415, /* Vendor */
|
||||
"Service-Information", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_GROUPED /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
|
||||
}
|
||||
|
||||
/* PS-Information */
|
||||
{
|
||||
/*
|
||||
Grouped. Its purpose is to allow the transmission
|
||||
of additional PS service specific information
|
||||
elements (3GPP 32.299 Rel7).
|
||||
*/
|
||||
|
||||
struct dict_avp_data data = {
|
||||
874, /* Code */
|
||||
10415, /* Vendor */
|
||||
"PS-Information", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_GROUPED /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
|
||||
}
|
||||
|
||||
/* PDP-Address */
|
||||
{
|
||||
/*
|
||||
Address. Present only in the initial CCR. Contains
|
||||
the user equipment IP address. This AVP is
|
||||
defined in 3GPP 32.299 Rel7.
|
||||
*/
|
||||
|
||||
struct dict_avp_data data = {
|
||||
1227, /* Code */
|
||||
10415, /* Vendor */
|
||||
"PDP-Address", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , Address_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-IMSI */
|
||||
{
|
||||
/*
|
||||
IMSI encoded in UTF-8 per 3GPP TS 23.003. No
|
||||
padding. Maximum length of data: 15.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
1, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-IMSI", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-Charging-Id */
|
||||
{
|
||||
/*
|
||||
Unsigned32. (3GPP TS 29.061 Rel7) . The
|
||||
charging identifier for the PDP context. The Flexi
|
||||
ISN generates the 3GPP charging ID for both
|
||||
virtual and normal PDP contexts with one excep-
|
||||
tion. If the Flexi ISN acts as a NAS server and the
|
||||
charging ID selection is set to NAS Client, the
|
||||
charging ID will be the NAand not the 3GPP charging ID of Flexi ISN.
|
||||
Present in the initial CCR only.S client
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
2, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-Charging-Id", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_UNSIGNED32 /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-PDP-Type */
|
||||
{
|
||||
/*
|
||||
Enumerated. (3GPP TS 29.061 Rel7 ). Type of
|
||||
PDP context, for example, IP or PPP. Present in
|
||||
the initial CCR only.
|
||||
0 = IPv4
|
||||
1 = PPP
|
||||
2 = IPv6
|
||||
3 = IPv4v6
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
3, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-PDP-Type", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_UNSIGNED32 /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-CG-Address */
|
||||
{
|
||||
/*
|
||||
OctetString. (3GPP TS 29.061 Rel4). The address
|
||||
of the charging gateway that has been marked as
|
||||
the default charging gateway for the PDP context.
|
||||
The address is expressed as a four-byte integer.
|
||||
Present in the initial CCR only.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
4, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-CG-Address", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , Address_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-GPRS-Negotiated-QoS-Profile */
|
||||
{
|
||||
/*
|
||||
UTF8String. (3GPP TS 29.061 Rel7 ). The QoS
|
||||
profile applied by the Flexi ISN. In update and ter-
|
||||
mination requests, this AVP is present only when
|
||||
the CCR has been triggered by a PDP context
|
||||
update affecting the negotiated QoS
|
||||
Each octet is described by two UTF-8-encoded
|
||||
characters denoting the hexadecimal
|
||||
representation.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
5, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-GPRS-Negotiated-QoS-Profile", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-SGSN-Address */
|
||||
{
|
||||
/*
|
||||
OctetString. (3GPP TS 29.061 Rel4). The address
|
||||
of the charging gateway that has been marked as
|
||||
the default charging gateway for the PDP context.
|
||||
The address is expressed as a four-byte integer.
|
||||
Present in the initial CCR only.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
6, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-SGSN-Address", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , Address_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-GGSN-Address */
|
||||
{
|
||||
/*
|
||||
OctetString. (3GPP TS 29.061 Rel4). Usually the
|
||||
IP address of Flexi ISN. The only exception is
|
||||
when the Flexi ISN acts as a NAS server and the
|
||||
charging ID selection is set to NAS Client; then the
|
||||
GGSN IP address will be the NAIP address. Present in the initial CCR only.S client
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
7, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-GGSN-Address", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , Address_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-IMSI-MCC-MNC */
|
||||
{
|
||||
/*
|
||||
UTF8String. MCC and MNC extracted from the
|
||||
user's IMSI (first 5 or 6 digits, as applicable from
|
||||
the presented IMSI). The MCC-MNCs are
|
||||
extracted from the tables configured in FlexiISN
|
||||
configuration under the General and Roaming
|
||||
configurations.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
8, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-IMSI-MCC-MNC", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-GGSN-MCC-MNC */
|
||||
{
|
||||
/*
|
||||
UTF8String. (3GPP TS 29.061 Rel7 ). Contains
|
||||
the mobile country and network code of the PLMN
|
||||
that the Flexi ISN belongs to. Present in the initial
|
||||
CCR only. The first entry in the list of local PLMNs
|
||||
in the Flexi ISN configuration determines the value
|
||||
of this AVP.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
9, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-GGSN-MCC-MNC", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-NSAPI */
|
||||
{
|
||||
/*
|
||||
UTF8String. (3GPP TS 29.061 Rel7 ). Indicates
|
||||
the NSAPI of the PDP context. Contains one octet
|
||||
consisting of a single digit. Present in the initial
|
||||
CCR only.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
10, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-NSAPI", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-Session-Stop-Indicator */
|
||||
{
|
||||
/*
|
||||
OctetString. (3GPP TS 29.061 Rel4). The
|
||||
presence of this AVP indicates that the last
|
||||
context of the PDP session has been deleted. May
|
||||
be present in the termination CCR only. Contains
|
||||
one octet that has a value of 0xff.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
11, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-Session-Stop-Indicator", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-Selection-Mode */
|
||||
{
|
||||
/*
|
||||
UTF8String. (3GPP TS 29.061 Rel7 ). Consists of
|
||||
one octet containing the selection mode as
|
||||
received from SGSN in the Create PDP Context
|
||||
Request. Present in the initial CCR only.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
12, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-Selection-Mode", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-Charging-Characteristics */
|
||||
{
|
||||
/*
|
||||
UTF8String. (3GPP TS 29.061 Rel7 ). The
|
||||
charging characteristics for the PDP context.
|
||||
Present in the initial CCR only. Consists of four
|
||||
octets. Each octet contains a single UTF-8
|
||||
encoded digit. The content of the charging charac-
|
||||
teristics is described in 3GPP TS 32.215.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
13, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-Charging-Characteristics", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-CG-IPv6-Address */
|
||||
{
|
||||
/*
|
||||
UTF8String.. (3GPP TS 29.061 Rel? (<=10) ). The
|
||||
IPv6 address of the charging gateway.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
14, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-CG-IPv6-Address", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-SGSN-IPv6-Address */
|
||||
{
|
||||
/*
|
||||
UTF8String.. (3GPP TS 29.061 Rel? (<=10) ). The
|
||||
IPv6 address of the SGSN.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
15, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-SGSN-IPv6-Address", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-GGSN-IPv6-Address */
|
||||
{
|
||||
/*
|
||||
UTF8String.. (3GPP TS 29.061 Rel? (<=10) ). The
|
||||
IPv6 address of the GGSN.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
16, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-GGSN-IPv6-Address", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-GGSN-IPv6-DNS-Servers */
|
||||
{
|
||||
/*
|
||||
UTF8String.. (3GPP TS 29.061 Rel? (<=10) ). List
|
||||
of IPv6 addresses of DNS servers for an APN in
|
||||
order of preference (max. 15 servers, 16 bytes
|
||||
each).
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
17, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-GGSN-IPv6-DNS-Servers", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-SGSN-MCC-MNC */
|
||||
{
|
||||
/*
|
||||
UTF8String. (3GPP TS 29.061 Rel7 ). MCC and
|
||||
MNC extracted from the RAI within Create or
|
||||
Update PDP Context Request. In update and ter-
|
||||
mination requests, this AVP is present only when
|
||||
the CCR has been triggered by a routing area
|
||||
update.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
18, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-SGSN-MCC-MNC", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
|
||||
}
|
||||
|
||||
/* Missing: 3GPP-Teardown-Indicator (19) */
|
||||
|
||||
/* 3GPP-IMEISV */
|
||||
{
|
||||
/*
|
||||
IMEI(SV) encoded as sequence of UTF8 characters.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
20, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-IMEISV", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-RAT-Type */
|
||||
{
|
||||
/*
|
||||
OctetString. (3GPP TS 29.061 Rel7 ) Defines the
|
||||
method used to access the network. Consists of a
|
||||
single octet. The following values may be sent:
|
||||
UTRAN (1), GERAN (2), WLAN (3), NAS (254),
|
||||
Unspecified (255).
|
||||
This AVP is included in the initial CCR and in
|
||||
update or termination CCRs if the value changes.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
21, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-RAT-Type", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-User-Location-Info */
|
||||
{
|
||||
/*
|
||||
OctetString. (3GPP TS 29.061 Rel7 ) Contains
|
||||
information about the user's current geographical
|
||||
location as received from the SGSN. Present
|
||||
always in initial CCR if the value is known and in
|
||||
update and termination CCRs if the value
|
||||
changes.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
22, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-User-Location-Info", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
|
||||
}
|
||||
|
||||
/* 3GPP-MS-TimeZone */
|
||||
{
|
||||
/*
|
||||
OctetString. (3GPP TS 29.061 Rel7 ) 3GPP-MS-
|
||||
TimeZone is AVP is present always in the initial CCR if the
|
||||
value is known and in the update and termination
|
||||
CCRs if the value changes. This IE is encoded
|
||||
according to 3GPP TS 29.061 Rel7
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
23, /* Code */
|
||||
10415, /* Vendor */
|
||||
"3GPP-MS-TimeZone", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
|
||||
}
|
||||
|
||||
/* Missing: 3GPP-CAMEL-Charging-Info (24) */
|
||||
/* Missing: 3GPP-Packet-Filter (25) */
|
||||
/* Missing: 3GPP-Negotiated-DSCP (26) */
|
||||
/* Missing: 3GPP-Allocate-IP-Type (27) */
|
||||
|
||||
/* PDP-Context-Type */
|
||||
{
|
||||
/*
|
||||
Enumerated. Indicates the type of a PDP context
|
||||
and is only included in CCR initial.
|
||||
|
||||
values are 0 for primary and 1 for secondary
|
||||
(3GPP 32.299 Rel7)
|
||||
*/
|
||||
struct dict_object *type;
|
||||
struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(PDP-Context-Type)" , NULL, NULL, NULL };
|
||||
struct dict_enumval_data t_0 = { "PRIMARY", { .i32 = 0 }};
|
||||
struct dict_enumval_data t_1 = { "SECONDARY", { .i32 = 1 }};
|
||||
|
||||
struct dict_avp_data data = {
|
||||
1247, /* Code */
|
||||
10415, /* Vendor */
|
||||
"PDP-Context-Type", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_INTEGER32 /* base type of data */
|
||||
};
|
||||
/* Create the Enumerated type, and then the AVP */
|
||||
CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type);
|
||||
CHECK_dict_new( DICT_ENUMVAL, &t_0 , type, NULL);
|
||||
CHECK_dict_new( DICT_ENUMVAL, &t_1 , type, NULL);
|
||||
CHECK_dict_new( DICT_AVP, &data , type, NULL);
|
||||
}
|
||||
|
||||
/* IMS-Information */
|
||||
{
|
||||
/*
|
||||
Grouped. Its purpose is to allow the transmission
|
||||
of additional IMS service specific information ele-
|
||||
ments. (3GPP 32.299 Rel7)
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
876, /* Code */
|
||||
10415, /* Vendor */
|
||||
"IMS-Information", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_GROUPED /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
|
||||
}
|
||||
|
||||
/* IMS-Charging-Identifier */
|
||||
{
|
||||
/*
|
||||
UTF8String. Contains the IMS charging identifier
|
||||
as given to the Flexi ISN by the IMS. This AVP is
|
||||
defined in 3GPP TS 32.225. This AVP is present
|
||||
in IMS sessions only. Present in the initial CCR
|
||||
only.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
841, /* Code */
|
||||
10415, /* Vendor */
|
||||
"IMS-Charging-Identifier", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_OCTETSTRING /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Max-Requested-Bandwidth-UL */
|
||||
{
|
||||
/*
|
||||
Unsigned32. The Max-Requested-Bandwidth-
|
||||
UL/DL AVP indicates the maximum allowed bit
|
||||
rate (in bits per second) for the uplink direction.
|
||||
(Re-used from 3GPP 29.214)
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
516, /* Code */
|
||||
10415, /* Vendor */
|
||||
"Max-Requested-Bandwidth-UL", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_UNSIGNED32 /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
|
||||
}
|
||||
|
||||
/* Max-Requested-Bandwidth-DL */
|
||||
{
|
||||
/*
|
||||
Unsigned32. The Max-Requested-Bandwidth-
|
||||
UL/DL AVP indicates the maximum allowed bit
|
||||
rate (in bits per second) for the uplink direction.
|
||||
*/
|
||||
struct dict_avp_data data = {
|
||||
515, /* Code */
|
||||
10415, /* Vendor */
|
||||
"Max-Requested-Bandwidth-DL", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */
|
||||
AVP_TYPE_UNSIGNED32 /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
|
||||
}
|
||||
|
||||
/* QoS-Information */
|
||||
{
|
||||
/*
|
||||
Grouped. This is the QoS that the DCCA
|
||||
server requests from Flexi ISN to be applied for
|
||||
this PDP context. This AVP and all AVPs con-
|
||||
tained within are described in 3GPP TS 29.212
|
||||
Release 7. The ARP AVP is introduced with
|
||||
Release 8. The relevant types are defined on
|
||||
table 5.3.1 of TS 29.212.
|
||||
*/
|
||||
|
||||
struct dict_avp_data data = {
|
||||
1016, /* Code */
|
||||
10415, /* Vendor */
|
||||
"QoS-Information", /* Name */
|
||||
AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */
|
||||
AVP_FLAG_VENDOR, /* Fixed flag values */
|
||||
AVP_TYPE_GROUPED /* base type of data */
|
||||
};
|
||||
CHECK_dict_new( DICT_AVP, &data , NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
TRACE_DEBUG(INFO, "Extension 'Dictionary definitions for DCCA 3GPP' initialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXTENSION_ENTRY("dict_dcca_3gpp", dict_dcca_3gpp_entry, "dict_dcca");
|
||||
3789
plat/diameter/extensions/sh_app/gx_app.c
Normal file
3789
plat/diameter/extensions/sh_app/gx_app.c
Normal file
File diff suppressed because it is too large
Load Diff
965
plat/diameter/extensions/sh_app/sh_app.c
Normal file
965
plat/diameter/extensions/sh_app/sh_app.c
Normal file
@@ -0,0 +1,965 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/*
|
||||
* Test application for freeDiameter.
|
||||
*/
|
||||
|
||||
#include "sh_app.h"
|
||||
#include "sh_conf.h"
|
||||
|
||||
|
||||
/* Initialize the configuration */
|
||||
struct ta_conf * ta_conf = NULL;
|
||||
static struct ta_conf _conf;
|
||||
static pthread_t ta_stats_th = (pthread_t)NULL;
|
||||
#if 0
|
||||
static int ta_init_peer_addr(struct peer_info* inf)
|
||||
{
|
||||
// uint16_t str;
|
||||
// int ev;
|
||||
|
||||
/* Initialize the server addresses */
|
||||
{
|
||||
struct addrinfo hints, *ai, *aip;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_flags = AI_NUMERICSERV;
|
||||
hints.ai_family = AF_INET;
|
||||
getaddrinfo("localhost", _stringize(TEST_PORT), &hints, &ai);
|
||||
aip = ai;
|
||||
while (aip) {
|
||||
ASSERT( 0 == fd_ep_add_merge( &inf->pi_endpoints, aip->ai_addr, aip->ai_addrlen, EP_FL_DISC | EP_ACCEPTALL ));
|
||||
aip = aip->ai_next;
|
||||
};
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
/* fj added 20170114. when the peer was free. we can reconnect to peer here*/
|
||||
static void peer_free_cb(struct peer_info *died_peer, void *cb_data)
|
||||
{
|
||||
LOG_N("peer_free_cb.%p %p", died_peer, cb_data);
|
||||
SH_CONF_S *ptr = (SH_CONF_S *)cb_data;
|
||||
if(NULL == died_peer && MODE_CLI == ta_conf->mode)
|
||||
{
|
||||
struct peer_info inf;
|
||||
memset(&inf, 0, sizeof(inf));
|
||||
inf.pi_diamid = strdup(ptr->pi_diamid_peer);//strdup(g_sh_conf_ext.pi_diamid_peer);
|
||||
inf.config.pic_flags.sec = PI_SEC_NONE;
|
||||
inf.config.pic_port = ptr->peer_port;
|
||||
// ta_init_peer_addr( (struct peer_info*)(&inf.pi_endpoints) );
|
||||
|
||||
ASSERT( 0 == fd_peer_add(&inf, __FILE__, peer_free_cb, ptr));//NULL));
|
||||
}
|
||||
}
|
||||
static int ta_conf_init(void)
|
||||
{
|
||||
ta_conf = &_conf;
|
||||
memset(ta_conf, 0, sizeof(struct ta_conf));
|
||||
|
||||
/* Set the default values */
|
||||
ta_conf->vendor_id = SH_VND_ID;
|
||||
ta_conf->appli_id = SH_APP_ID;
|
||||
ta_conf->cmd_id = 0xfffffe;
|
||||
ta_conf->avp_id = 0xffffff;
|
||||
ta_conf->long_avp_len = 5000;
|
||||
|
||||
ta_conf->mode = g_sh_conf_ext.mode;
|
||||
/* fj added 20170114. only diameter client connect to peer. In this case, connect to peer when started. */
|
||||
if(MODE_CLI == ta_conf->mode)
|
||||
{
|
||||
if (g_sh_conf_ext.pi_diamid_peer != NULL)
|
||||
{
|
||||
struct peer_info inf;
|
||||
memset(&inf, 0, sizeof(inf));
|
||||
inf.pi_diamid = strdup(g_sh_conf_ext.pi_diamid_peer);
|
||||
inf.config.pic_flags.sec = PI_SEC_NONE;
|
||||
inf.config.pic_port = g_sh_conf_ext.peer_port;
|
||||
// ta_init_peer_addr( (struct peer_info*)(&inf.pi_endpoints) );
|
||||
|
||||
ASSERT( 0 == fd_peer_add(&inf, __FILE__, peer_free_cb, &g_sh_conf_ext));
|
||||
}
|
||||
|
||||
int i=0;
|
||||
SH_CONF_S *pcfg = NULL;
|
||||
for (i=0; i<rolkset.smslknum; i++)
|
||||
{
|
||||
pcfg = &rolkset.smslk[i].cfg;
|
||||
if (pcfg->pi_diamid_peer != NULL)
|
||||
{
|
||||
struct peer_info inf;
|
||||
memset(&inf, 0, sizeof(inf));
|
||||
inf.pi_diamid = strdup(pcfg->pi_diamid_peer);
|
||||
inf.config.pic_flags.sec = PI_SEC_NONE;
|
||||
inf.config.pic_port = pcfg->peer_port;
|
||||
// ta_init_peer_addr( (struct peer_info*)(&inf.pi_endpoints) );
|
||||
|
||||
ASSERT( 0 == fd_peer_add(&inf, __FILE__, peer_free_cb, pcfg));
|
||||
}
|
||||
}
|
||||
for (i=0; i<rolkset.voicelknum; i++)
|
||||
{
|
||||
pcfg = &rolkset.voicelk[i].cfg;
|
||||
if (pcfg->pi_diamid_peer != NULL)
|
||||
{
|
||||
struct peer_info inf;
|
||||
memset(&inf, 0, sizeof(inf));
|
||||
inf.pi_diamid = strdup(pcfg->pi_diamid_peer);
|
||||
inf.config.pic_flags.sec = PI_SEC_NONE;
|
||||
inf.config.pic_port = pcfg->peer_port;
|
||||
// ta_init_peer_addr( (struct peer_info*)(&inf.pi_endpoints) );
|
||||
|
||||
ASSERT( 0 == fd_peer_add(&inf, __FILE__, peer_free_cb, pcfg));
|
||||
}
|
||||
}
|
||||
/*if (g_rosms_conf_ext.pi_diamid_peer != NULL)
|
||||
{
|
||||
struct peer_info inf;
|
||||
memset(&inf, 0, sizeof(inf));
|
||||
inf.pi_diamid = strdup(g_rosms_conf_ext.pi_diamid_peer);
|
||||
inf.config.pic_flags.sec = PI_SEC_NONE;
|
||||
inf.config.pic_port = g_rosms_conf_ext.peer_port;
|
||||
// ta_init_peer_addr( (struct peer_info*)(&inf.pi_endpoints) );
|
||||
|
||||
ASSERT( 0 == fd_peer_add(&inf, __FILE__, peer_free_cb, &g_rosms_conf_ext));
|
||||
}
|
||||
|
||||
if (g_rovoice_conf_ext.pi_diamid_peer != NULL)
|
||||
{
|
||||
struct peer_info inf;
|
||||
memset(&inf, 0, sizeof(inf));
|
||||
inf.pi_diamid = strdup(g_rovoice_conf_ext.pi_diamid_peer);
|
||||
inf.config.pic_flags.sec = PI_SEC_NONE;
|
||||
inf.config.pic_port = g_rovoice_conf_ext.peer_port;
|
||||
// ta_init_peer_addr( (struct peer_info*)(&inf.pi_endpoints) );
|
||||
|
||||
ASSERT( 0 == fd_peer_add(&inf, __FILE__, peer_free_cb, &g_rovoice_conf_ext));
|
||||
}*/
|
||||
}
|
||||
|
||||
ta_conf->dest_realm = strdup(fd_g_config->cnf_diamrlm);
|
||||
ta_conf->signal = TEST_APP_DEFAULT_SIGNAL;
|
||||
ta_conf->bench_concur = 100;
|
||||
ta_conf->bench_duration = 10;
|
||||
|
||||
/* Initialize the mutex */
|
||||
CHECK_POSIX( pthread_mutex_init(&ta_conf->stats_lock, NULL) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ta_conf_dump(void)
|
||||
{
|
||||
if (!TRACE_BOOL(INFO))
|
||||
return;
|
||||
fd_log_debug( "------- app_test configuration dump: ---------");
|
||||
fd_log_debug( " Vendor Id .......... : %u", ta_conf->vendor_id);
|
||||
fd_log_debug( " Application Id ..... : %u", ta_conf->appli_id);
|
||||
fd_log_debug( " Command Id ......... : %u", ta_conf->cmd_id);
|
||||
fd_log_debug( " AVP Id ............. : %u", ta_conf->avp_id);
|
||||
fd_log_debug( " Long AVP Id ........ : %u", ta_conf->long_avp_id);
|
||||
fd_log_debug( " Long AVP len ....... : %zu", ta_conf->long_avp_len);
|
||||
fd_log_debug( " Mode ............... : %s%s%s", ta_conf->mode & MODE_SERV ? "Serv" : "", ta_conf->mode & MODE_CLI ? "Cli" : "", ta_conf->mode & MODE_BENCH ? " (Benchmark)" : "");
|
||||
fd_log_debug( " Destination Realm .. : %s", ta_conf->dest_realm ?: "- none -");
|
||||
fd_log_debug( " Destination Host ... : %s", ta_conf->dest_host ?: "- none -");
|
||||
fd_log_debug( " Signal ............. : %i", ta_conf->signal);
|
||||
fd_log_debug( "------- /app_test configuration dump ---------");
|
||||
}
|
||||
|
||||
/* Function to display statistics periodically */
|
||||
static void * ta_stats(void * arg) {
|
||||
|
||||
struct timespec start, now;
|
||||
struct ta_stats copy;
|
||||
|
||||
/* Get the start time */
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &start), );
|
||||
|
||||
/* Now, loop until canceled */
|
||||
while (1) {
|
||||
/* Display statistics every XX seconds */
|
||||
sleep(ta_conf->bench_duration + 3);
|
||||
|
||||
/* Now, get the current stats */
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), );
|
||||
memcpy(©, &ta_conf->stats, sizeof(struct ta_stats));
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), );
|
||||
|
||||
/* Get the current execution time */
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), );
|
||||
|
||||
/* Now, display everything */
|
||||
fd_log_debug( "------- app_test statistics ---------");
|
||||
if (now.tv_nsec >= start.tv_nsec) {
|
||||
fd_log_debug( " Executing for: %d.%06ld sec",
|
||||
(int)(now.tv_sec - start.tv_sec),
|
||||
(long)(now.tv_nsec - start.tv_nsec) / 1000);
|
||||
} else {
|
||||
fd_log_debug( " Executing for: %d.%06ld sec",
|
||||
(int)(now.tv_sec - 1 - start.tv_sec),
|
||||
(long)(now.tv_nsec + 1000000000 - start.tv_nsec) / 1000);
|
||||
}
|
||||
|
||||
if (ta_conf->mode & MODE_SERV) {
|
||||
fd_log_debug( " Server: %llu message(s) echoed", copy.nb_echoed);
|
||||
}
|
||||
if (ta_conf->mode & MODE_CLI) {
|
||||
fd_log_debug( " Client:");
|
||||
fd_log_debug( " %llu message(s) sent", copy.nb_sent);
|
||||
fd_log_debug( " %llu error(s) received", copy.nb_errs);
|
||||
fd_log_debug( " %llu answer(s) received", copy.nb_recv);
|
||||
fd_log_debug( " fastest: %ld.%06ld sec.", copy.shortest / 1000000, copy.shortest % 1000000);
|
||||
fd_log_debug( " slowest: %ld.%06ld sec.", copy.longest / 1000000, copy.longest % 1000000);
|
||||
fd_log_debug( " Average: %ld.%06ld sec.", copy.avg / 1000000, copy.avg % 1000000);
|
||||
}
|
||||
fd_log_debug( "-------------------------------------");
|
||||
}
|
||||
|
||||
return NULL; /* never called */
|
||||
}
|
||||
|
||||
static struct fd_hook_hdl * hookhdl[2] = { NULL, NULL };
|
||||
static void ta_hook_cb_silent(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata) {
|
||||
}
|
||||
static void ta_hook_cb_oneline(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata) {
|
||||
char * buf = NULL;
|
||||
size_t len;
|
||||
|
||||
CHECK_MALLOC_DO( fd_msg_dump_summary(&buf, &len, NULL, msg, NULL, 0, 0),
|
||||
{ LOG_E("Error while dumping a message"); return; } );
|
||||
|
||||
LOG_N("{%d} %s: %s", type, (char *)other ?:"<nil>", buf ?:"<nil>");
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
extern int sh_dict_init(char * conffile);
|
||||
extern int dict_dcca_3gpp_entry(char * conffile);
|
||||
extern int dict_dcca_entry(char * conffile);
|
||||
extern struct dict_object * sh_appli;
|
||||
extern struct dict_object * sh_vendor;
|
||||
extern struct dict_object *hw_vendor;
|
||||
extern struct dict_object *uname_vendor_5535;
|
||||
|
||||
|
||||
extern int app_gx_entry(char * conffile);
|
||||
/* entry point */
|
||||
static int ta_entry(char * conffile)
|
||||
{
|
||||
TRACE_ENTRY("%p", conffile);
|
||||
|
||||
/* Initialize configuration */
|
||||
CHECK_FCT( ta_conf_init() );
|
||||
|
||||
/* Parse configuration file */
|
||||
/* fj added 2016/06/21 */
|
||||
#if 0
|
||||
if (conffile != NULL) {
|
||||
CHECK_FCT( ta_conf_handle(conffile) );
|
||||
}
|
||||
#endif
|
||||
|
||||
TRACE_DEBUG(INFO, "Extension Test_App initialized with configuration: '%s'", conffile);
|
||||
ta_conf_dump();
|
||||
|
||||
/* Install objects definitions for this test application */
|
||||
#if 0
|
||||
CHECK_FCT( ta_dict_init() );
|
||||
#else
|
||||
CHECK_FCT( sh_dict_init(NULL) );
|
||||
CHECK_FCT( dict_dcca_3gpp_entry(NULL) );
|
||||
CHECK_FCT( dict_dcca_entry(NULL) );
|
||||
#endif
|
||||
|
||||
/* gx entry */
|
||||
app_gx_entry(NULL);
|
||||
|
||||
|
||||
/* Install the handlers for incoming messages */
|
||||
if (ta_conf->mode & MODE_SERV) {
|
||||
CHECK_FCT( sh_serv_init() );
|
||||
}
|
||||
|
||||
/* Start the signal handler thread */
|
||||
if (ta_conf->mode & MODE_CLI) {
|
||||
if (ta_conf->mode & MODE_BENCH) {
|
||||
CHECK_FCT( ta_bench_init() );
|
||||
} else {
|
||||
CHECK_FCT( sh_cli_init() );
|
||||
}
|
||||
}
|
||||
|
||||
/* Advertise the support for the test application in the peer */
|
||||
CHECK_FCT( fd_disp_app_support ( sh_appli, sh_vendor, 1, 0 ) );
|
||||
|
||||
CHECK_FCT( fd_disp_app_support ( sh_appli, hw_vendor, 1, 0 ) );
|
||||
|
||||
CHECK_FCT( fd_disp_app_support ( sh_appli, uname_vendor_5535, 1, 0 ) );
|
||||
|
||||
if (ta_conf->mode & MODE_BENCH) {
|
||||
/* Register an empty hook to disable the default handling */
|
||||
CHECK_FCT( fd_hook_register( HOOK_MASK( HOOK_DATA_RECEIVED, HOOK_MESSAGE_RECEIVED, HOOK_MESSAGE_LOCAL, HOOK_MESSAGE_SENT, HOOK_MESSAGE_ROUTING_FORWARD, HOOK_MESSAGE_ROUTING_LOCAL ),
|
||||
ta_hook_cb_silent, NULL, NULL, &hookhdl[0]) );
|
||||
CHECK_FCT( fd_hook_register( HOOK_MASK( HOOK_MESSAGE_ROUTING_ERROR, HOOK_MESSAGE_DROPPED ),
|
||||
ta_hook_cb_oneline, NULL, NULL, &hookhdl[1]) );
|
||||
|
||||
}
|
||||
|
||||
/* Start the statistics thread */
|
||||
CHECK_POSIX( pthread_create(&ta_stats_th, NULL, ta_stats, NULL) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unload */
|
||||
void fd_ext_fini(void)
|
||||
{
|
||||
if (ta_conf->mode & MODE_CLI)
|
||||
sh_cli_finit();
|
||||
if (ta_conf->mode & MODE_SERV)
|
||||
sh_serv_fini();
|
||||
if (hookhdl[0])
|
||||
fd_hook_unregister( hookhdl[0] );
|
||||
if (hookhdl[1])
|
||||
fd_hook_unregister( hookhdl[1] );
|
||||
CHECK_FCT_DO( fd_thr_term(&ta_stats_th), );
|
||||
CHECK_POSIX_DO( pthread_mutex_destroy(&ta_conf->stats_lock), );
|
||||
}
|
||||
|
||||
/*
|
||||
* fj added 2016/06/21
|
||||
* parse config file
|
||||
*
|
||||
*/
|
||||
|
||||
/* fj added 2016/06/20 */
|
||||
/* The cryptographic data */
|
||||
static char ca_data[] = "-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIEqjCCA5KgAwIBAgIJANKgDwdlDYQDMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD\n"
|
||||
"VQQGEwJKUDEOMAwGA1UECAwFVG9reW8xEDAOBgNVBAcMB0tvZ2FuZWkxDTALBgNV\n"
|
||||
"BAoMBFdJREUxDzANBgNVBAsMBkFBQSBXRzEfMB0GA1UEAwwWY2hhdnJvdXguY293\n"
|
||||
"YWRkaWN0Lm9yZzEiMCAGCSqGSIb3DQEJARYTc2RlY3VnaXNAbmljdC5nby5qcDAe\n"
|
||||
"Fw0wOTEwMDUwODUxNDRaFw0xOTEwMDMwODUxNDRaMIGUMQswCQYDVQQGEwJKUDEO\n"
|
||||
"MAwGA1UECAwFVG9reW8xEDAOBgNVBAcMB0tvZ2FuZWkxDTALBgNVBAoMBFdJREUx\n"
|
||||
"DzANBgNVBAsMBkFBQSBXRzEfMB0GA1UEAwwWY2hhdnJvdXguY293YWRkaWN0Lm9y\n"
|
||||
"ZzEiMCAGCSqGSIb3DQEJARYTc2RlY3VnaXNAbmljdC5nby5qcDCCASIwDQYJKoZI\n"
|
||||
"hvcNAQEBBQADggEPADCCAQoCggEBAM5c6w4NnngTvGNWcJzbo0Kklp+kvUNQNgGu\n"
|
||||
"myvz826qPp07HTSyJrIcgFnuYDR0Nd130Ot9u5osqpQhHTvolxDE87Tii8i3hJSj\n"
|
||||
"TTY9K0ZwGb4AZ6QkuyMXS1jtOY657HqjpGZqT/2Syh0i7dM/hqSXFw0SPbyq+W1H\n"
|
||||
"SVFWa1CTkPywFWAzwdr5WKah77uZ1dxWqgPgUdcZOiIQtLRp5n3fg40Nwso5YdwS\n"
|
||||
"64+ebBX1pkhrCQ8AGc8O61Ep1JTXcO7jqQmPgzjiN+FeostI1Dp73S3MqleTAHjR\n"
|
||||
"hqZ77VF7nkroMM9btMHJBaxnfwc2ewULUJwnuOiGWrvMq/9Z4J8CAwEAAaOB/DCB\n"
|
||||
"+TAdBgNVHQ4EFgQUkqpVn7N3gmiJ7X5zQ2bki+7qv4UwgckGA1UdIwSBwTCBvoAU\n"
|
||||
"kqpVn7N3gmiJ7X5zQ2bki+7qv4WhgZqkgZcwgZQxCzAJBgNVBAYTAkpQMQ4wDAYD\n"
|
||||
"VQQIDAVUb2t5bzEQMA4GA1UEBwwHS29nYW5laTENMAsGA1UECgwEV0lERTEPMA0G\n"
|
||||
"A1UECwwGQUFBIFdHMR8wHQYDVQQDDBZjaGF2cm91eC5jb3dhZGRpY3Qub3JnMSIw\n"
|
||||
"IAYJKoZIhvcNAQkBFhNzZGVjdWdpc0BuaWN0LmdvLmpwggkA0qAPB2UNhAMwDAYD\n"
|
||||
"VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAJy0XLk8j8YLSTt2/VMy9TAUx\n"
|
||||
"esXUiZj0Ung+gkr7A1K0NnwYxDzG2adMhf13upHoydu2ErLMmD6F77x+QuY/q7nc\n"
|
||||
"ZvO0tvcoAP6ToSDwiypU5dnTmnfkgwVwzFkNCi1sGRosEm8c/c/8MfK0I0nVdj1/\n"
|
||||
"BIkIG7tTDVi9JvkWYl0UlSKWTZKrntVwCmscfC02DGb+GoLbO9+QmiNM5Y3yOYZ4\n"
|
||||
"Pc7SSoKLL0rwJBmpPNs7boYsweeSuCAVu0shRfgC90odXcej2EN5ETfCuU1evXNW\n"
|
||||
"5cA+zZsDK/nWJwxBaW0CxAHX579FElFWlK4+BnzhZRdDhmJDnN5dh4ekJGM6Lg==\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
/* Client:
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 5 (0x5)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: C=JP, ST=Tokyo, L=Koganei, O=WIDE, OU=AAA WG, CN=chavroux.cowaddict.org/emailAddress=sdecugis@nict.go.jp
|
||||
Validity
|
||||
Not Before: Oct 27 04:04:05 2009 GMT
|
||||
Not After : Oct 25 04:04:05 2019 GMT
|
||||
Subject: C=JP, ST=Tokyo, L=Koganei, O=WIDE, OU=AAA WG, CN=client.test/emailAddress=client@test
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
RSA Public Key: (1024 bit)
|
||||
Modulus (1024 bit):
|
||||
00:bd:eb:50:1e:9d:7a:cd:9d:bb:e7:bc:4e:38:4a:
|
||||
b2:cc:9e:b4:89:77:01:ef:d1:c6:19:29:00:fe:ce:
|
||||
3c:62:05:13:b1:8c:ff:31:7a:0f:c1:2e:4b:3c:0c:
|
||||
40:1e:36:4e:76:da:0a:64:43:fc:1e:ea:0c:97:b2:
|
||||
57:9c:9c:8c:90:bd:eb:23:7b:b8:b7:5c:03:ed:6f:
|
||||
48:55:8a:88:08:38:c5:cd:33:b7:ab:a8:3a:6f:7f:
|
||||
13:10:65:a5:50:b9:f4:8b:cc:2e:e9:79:58:a6:11:
|
||||
f0:58:45:41:ef:36:b3:35:cb:14:ec:82:0c:ad:11:
|
||||
6a:ea:64:ef:28:a2:6e:47:45
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
Netscape Comment:
|
||||
OpenSSL Generated Certificate
|
||||
X509v3 Subject Key Identifier:
|
||||
BE:B3:89:4F:9D:8F:6C:20:C4:D0:3E:6A:05:11:82:50:54:49:70:A2
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:92:AA:55:9F:B3:77:82:68:89:ED:7E:73:43:66:E4:8B:EE:EA:BF:85
|
||||
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
a3:88:f5:15:b5:ad:20:60:a1:85:19:3f:b9:5e:1e:be:31:7f:
|
||||
84:7a:c2:18:3a:63:6a:67:1f:46:86:4d:10:d6:1d:ad:a2:c8:
|
||||
0b:95:33:fa:e4:05:f4:b8:70:34:77:f7:85:6e:70:46:ac:39:
|
||||
54:a9:5f:ea:5e:d1:33:bb:c9:a3:42:81:41:90:25:b5:92:8b:
|
||||
e8:6e:3e:97:06:dd:9a:cc:29:61:34:5a:d3:1c:5d:ad:d1:a3:
|
||||
eb:6a:47:b4:d0:c2:17:89:e1:e2:2d:36:18:50:1a:e7:d4:fc:
|
||||
38:2e:47:0b:39:50:87:2f:aa:07:64:f8:9a:4d:47:01:da:10:
|
||||
d8:97:c7:a6:13:bc:0e:ca:63:c1:f2:09:fb:f8:6a:a4:5f:08:
|
||||
b5:ad:ed:4f:71:b9:89:7f:43:27:85:72:e7:8d:a8:4a:cc:f6:
|
||||
36:ca:8a:ae:82:b5:a8:42:41:99:87:84:7c:f0:90:fd:ca:96:
|
||||
37:a2:e0:d9:fa:dd:a4:c9:f1:50:b7:e5:e6:8f:af:83:8c:23:
|
||||
b6:20:cc:66:e3:08:60:13:02:8f:42:3a:07:91:a7:38:b2:72:
|
||||
16:fd:bd:a9:60:f0:e2:9f:23:f3:c0:99:e3:17:bc:00:7c:b3:
|
||||
89:9c:ea:fa:3e:f6:69:a1:98:c2:ec:46:da:70:b6:f9:c3:93:
|
||||
a7:fc:36:dd
|
||||
*/
|
||||
/*
|
||||
static char client_cert_data[] ="-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIDiTCCAnGgAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBlDELMAkGA1UEBhMCSlAx\n"
|
||||
"DjAMBgNVBAgMBVRva3lvMRAwDgYDVQQHDAdLb2dhbmVpMQ0wCwYDVQQKDARXSURF\n"
|
||||
"MQ8wDQYDVQQLDAZBQUEgV0cxHzAdBgNVBAMMFmNoYXZyb3V4LmNvd2FkZGljdC5v\n"
|
||||
"cmcxIjAgBgkqhkiG9w0BCQEWE3NkZWN1Z2lzQG5pY3QuZ28uanAwHhcNMDkxMDI3\n"
|
||||
"MDQwNDA1WhcNMTkxMDI1MDQwNDA1WjCBgTELMAkGA1UEBhMCSlAxDjAMBgNVBAgM\n"
|
||||
"BVRva3lvMRAwDgYDVQQHDAdLb2dhbmVpMQ0wCwYDVQQKDARXSURFMQ8wDQYDVQQL\n"
|
||||
"DAZBQUEgV0cxFDASBgNVBAMMC2NsaWVudC50ZXN0MRowGAYJKoZIhvcNAQkBFgtj\n"
|
||||
"bGllbnRAdGVzdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvetQHp16zZ27\n"
|
||||
"57xOOEqyzJ60iXcB79HGGSkA/s48YgUTsYz/MXoPwS5LPAxAHjZOdtoKZEP8HuoM\n"
|
||||
"l7JXnJyMkL3rI3u4t1wD7W9IVYqICDjFzTO3q6g6b38TEGWlULn0i8wu6XlYphHw\n"
|
||||
"WEVB7zazNcsU7IIMrRFq6mTvKKJuR0UCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglg\n"
|
||||
"hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O\n"
|
||||
"BBYEFL6ziU+dj2wgxNA+agURglBUSXCiMB8GA1UdIwQYMBaAFJKqVZ+zd4Joie1+\n"
|
||||
"c0Nm5Ivu6r+FMA0GCSqGSIb3DQEBBQUAA4IBAQCjiPUVta0gYKGFGT+5Xh6+MX+E\n"
|
||||
"esIYOmNqZx9Ghk0Q1h2tosgLlTP65AX0uHA0d/eFbnBGrDlUqV/qXtEzu8mjQoFB\n"
|
||||
"kCW1kovobj6XBt2azClhNFrTHF2t0aPrake00MIXieHiLTYYUBrn1Pw4LkcLOVCH\n"
|
||||
"L6oHZPiaTUcB2hDYl8emE7wOymPB8gn7+GqkXwi1re1PcbmJf0MnhXLnjahKzPY2\n"
|
||||
"yoqugrWoQkGZh4R88JD9ypY3ouDZ+t2kyfFQt+Xmj6+DjCO2IMxm4whgEwKPQjoH\n"
|
||||
"kac4snIW/b2pYPDinyPzwJnjF7wAfLOJnOr6PvZpoZjC7EbacLb5w5On/Dbd\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
static char client_priv_data[] ="-----BEGIN RSA PRIVATE KEY-----\n"
|
||||
"MIICXgIBAAKBgQC961AenXrNnbvnvE44SrLMnrSJdwHv0cYZKQD+zjxiBROxjP8x\n"
|
||||
"eg/BLks8DEAeNk522gpkQ/we6gyXslecnIyQvesje7i3XAPtb0hViogIOMXNM7er\n"
|
||||
"qDpvfxMQZaVQufSLzC7peVimEfBYRUHvNrM1yxTsggytEWrqZO8oom5HRQIDAQAB\n"
|
||||
"AoGBAIYnsOLPby3LnC5n8AEHkyHDgdgQvsd/MSYYtuFHIZRD7dNfu+xhQru9TdvO\n"
|
||||
"84Pj7K07/FczRuc3gUmu6wBv/UIP9To15RHZh+/n537nybGus5S4IYKVvap477To\n"
|
||||
"0rQDf9ec27iw77gxb7moQ9Otuxwbv0h0Z+1EVLI8d8jHOq0BAkEA9YNr0R+7KXBS\n"
|
||||
"48yT43g5HpOFkTZzNXWVdpSvYGneb56wslk5Eatp235I4uz/a7Rej5v99W0M3nSe\n"
|
||||
"/AgHfYn75QJBAMYH/pBx/WkrLj+pPaARlNwInCIC5zUhr6B0IKCt2tvy5eyuc5sd\n"
|
||||
"AoTFaU+cSI+ZqsRzY8jMKkonktxBg48oJ+ECQQCt4AtlqcFVkbVCm8pJGQXq/7Ni\n"
|
||||
"qlthiwr1Vkv2TkQ4bPza8pGWT/3Cc2ePPyWN08n8jw+G11p72cAW4mDbqfN5AkEA\n"
|
||||
"mNYKrkiLn+NnqlJf8W4gSUGL3uQGtYbuGRQHKnuDckWhFm39YzWcgAQsJvkjN1EN\n"
|
||||
"7thvpsWLzfeE7ODTPGVtgQJATObxYJOt6rms3fAStwuXW3ET77TA1ja4XsUEe5Yu\n"
|
||||
"JpcQOruJb9XwndqzNbL0dSUePb9gFiBCGKYOyreNTTRTmw==\n"
|
||||
"-----END RSA PRIVATE KEY-----\n";
|
||||
*/
|
||||
|
||||
/* Server:
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 4 (0x4)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: C=JP, ST=Tokyo, L=Koganei, O=WIDE, OU=AAA WG, CN=chavroux.cowaddict.org/emailAddress=sdecugis@nict.go.jp
|
||||
Validity
|
||||
Not Before: Oct 27 04:03:39 2009 GMT
|
||||
Not After : Oct 25 04:03:39 2019 GMT
|
||||
Subject: C=JP, ST=Tokyo, L=Koganei, O=WIDE, OU=AAA WG, CN=serv.test/emailAddress=serv@test
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
RSA Public Key: (1024 bit)
|
||||
Modulus (1024 bit):
|
||||
00:a6:f7:1c:a9:90:5b:fa:c8:f6:a3:04:0c:d0:8b:
|
||||
45:c3:90:f7:2d:c2:c9:d7:bd:66:8a:7c:1c:51:89:
|
||||
40:9e:cd:70:57:cb:00:47:a3:e8:76:8b:00:b3:c9:
|
||||
c3:0d:b1:b9:2a:08:9f:52:92:82:d3:18:c1:d8:d1:
|
||||
b8:1e:fd:71:fe:23:ec:19:e9:6d:9d:fd:ae:88:bc:
|
||||
39:44:7a:37:ad:c6:88:d1:64:7c:b1:d4:3c:a9:30:
|
||||
c4:de:51:02:c4:48:4f:25:3e:2f:93:ae:25:32:66:
|
||||
9a:dc:f4:44:45:ff:7f:12:49:97:0d:01:8d:13:9a:
|
||||
d3:8f:9e:2d:62:95:02:0a:c7
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
Netscape Comment:
|
||||
OpenSSL Generated Certificate
|
||||
X509v3 Subject Key Identifier:
|
||||
0C:33:C4:7F:39:D0:34:FF:F8:61:A1:46:8B:49:1D:A3:57:B3:4D:58
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:92:AA:55:9F:B3:77:82:68:89:ED:7E:73:43:66:E4:8B:EE:EA:BF:85
|
||||
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
87:f5:49:a6:04:f9:98:9a:f1:1a:68:ce:06:ae:4c:0c:08:eb:
|
||||
ba:98:e7:3f:df:22:7f:35:88:1d:b7:8a:f3:89:a3:68:0d:53:
|
||||
45:eb:23:a1:dd:6b:dc:b0:80:58:0c:10:0b:49:74:ea:a8:b6:
|
||||
8c:2e:c6:73:dc:7a:74:c7:59:3e:79:5a:d2:5c:15:0b:f1:d8:
|
||||
19:37:2a:c0:22:75:10:3f:4c:e9:a1:e0:eb:b2:9e:09:70:3d:
|
||||
2a:4c:fe:9c:99:36:4b:aa:6c:e1:8b:9c:aa:e1:29:1f:49:6b:
|
||||
14:db:12:ae:cf:68:4a:dd:03:e1:3b:ad:79:b4:54:84:1d:bb:
|
||||
ac:45:c4:85:f1:03:65:65:96:23:ae:e7:97:3c:5c:db:ce:55:
|
||||
34:5d:c3:73:ec:cd:f6:0f:a5:81:5f:c2:ab:a3:42:fa:36:7f:
|
||||
83:ef:db:0f:cd:62:0b:ea:d9:4f:73:35:68:5f:23:d5:0a:be:
|
||||
ff:7f:23:9a:af:0d:a5:f8:3e:3a:f0:63:1c:e1:d2:96:81:cf:
|
||||
7b:5a:6b:d0:9b:67:56:9e:aa:a9:e8:f1:6c:fb:54:2b:1a:f4:
|
||||
ef:16:5a:be:1d:a9:c8:d6:cc:f7:42:8c:fe:83:2c:84:8c:80:
|
||||
fb:1c:88:f6:35:1c:ae:43:72:fa:68:30:9c:25:8b:db:2c:84:
|
||||
87:76:9d:b9
|
||||
*/
|
||||
static char server_cert_data[] ="-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIDhDCCAmygAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBlDELMAkGA1UEBhMCSlAx\n"
|
||||
"DjAMBgNVBAgMBVRva3lvMRAwDgYDVQQHDAdLb2dhbmVpMQ0wCwYDVQQKDARXSURF\n"
|
||||
"MQ8wDQYDVQQLDAZBQUEgV0cxHzAdBgNVBAMMFmNoYXZyb3V4LmNvd2FkZGljdC5v\n"
|
||||
"cmcxIjAgBgkqhkiG9w0BCQEWE3NkZWN1Z2lzQG5pY3QuZ28uanAwHhcNMDkxMDI3\n"
|
||||
"MDQwMzM5WhcNMTkxMDI1MDQwMzM5WjB9MQswCQYDVQQGEwJKUDEOMAwGA1UECAwF\n"
|
||||
"VG9reW8xEDAOBgNVBAcMB0tvZ2FuZWkxDTALBgNVBAoMBFdJREUxDzANBgNVBAsM\n"
|
||||
"BkFBQSBXRzESMBAGA1UEAwwJc2Vydi50ZXN0MRgwFgYJKoZIhvcNAQkBFglzZXJ2\n"
|
||||
"QHRlc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKb3HKmQW/rI9qMEDNCL\n"
|
||||
"RcOQ9y3Cyde9Zop8HFGJQJ7NcFfLAEej6HaLALPJww2xuSoIn1KSgtMYwdjRuB79\n"
|
||||
"cf4j7BnpbZ39roi8OUR6N63GiNFkfLHUPKkwxN5RAsRITyU+L5OuJTJmmtz0REX/\n"
|
||||
"fxJJlw0BjROa04+eLWKVAgrHAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4\n"
|
||||
"QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBQM\n"
|
||||
"M8R/OdA0//hhoUaLSR2jV7NNWDAfBgNVHSMEGDAWgBSSqlWfs3eCaIntfnNDZuSL\n"
|
||||
"7uq/hTANBgkqhkiG9w0BAQUFAAOCAQEAh/VJpgT5mJrxGmjOBq5MDAjrupjnP98i\n"
|
||||
"fzWIHbeK84mjaA1TResjod1r3LCAWAwQC0l06qi2jC7Gc9x6dMdZPnla0lwVC/HY\n"
|
||||
"GTcqwCJ1ED9M6aHg67KeCXA9Kkz+nJk2S6ps4YucquEpH0lrFNsSrs9oSt0D4Tut\n"
|
||||
"ebRUhB27rEXEhfEDZWWWI67nlzxc285VNF3Dc+zN9g+lgV/Cq6NC+jZ/g+/bD81i\n"
|
||||
"C+rZT3M1aF8j1Qq+/38jmq8Npfg+OvBjHOHSloHPe1pr0JtnVp6qqejxbPtUKxr0\n"
|
||||
"7xZavh2pyNbM90KM/oMshIyA+xyI9jUcrkNy+mgwnCWL2yyEh3aduQ==\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
static char server_priv_data[] ="-----BEGIN RSA PRIVATE KEY-----\n"
|
||||
"MIICXQIBAAKBgQCm9xypkFv6yPajBAzQi0XDkPctwsnXvWaKfBxRiUCezXBXywBH\n"
|
||||
"o+h2iwCzycMNsbkqCJ9SkoLTGMHY0bge/XH+I+wZ6W2d/a6IvDlEejetxojRZHyx\n"
|
||||
"1DypMMTeUQLESE8lPi+TriUyZprc9ERF/38SSZcNAY0TmtOPni1ilQIKxwIDAQAB\n"
|
||||
"AoGAZv3Ddm0P79CLIt9asEFY1VvUvSuMqkGwwPfx1/HcJJkBFYapM4fN22G/Gyf3\n"
|
||||
"47ifSWhsLtklTeXVnVMwSh14dJaJQuSEnaFnUUWfjiRbEAXZnMFwAIiaszEZbPap\n"
|
||||
"NUNpcGl06FZrphYAMkjOVUfjCjfOZDAvL4JGpo271Zx4l0ECQQDYoFFQpBCPx0PK\n"
|
||||
"TWUmvatXI/Amo94XkGfofbdeeI8PiAJBO5UI6rmjjIVwsJwO9dQb/IlP1/OnBeJv\n"
|
||||
"p9YW5uixAkEAxVAOKu7mpGu0Q/K2iEUUYDX9YHf253kgkdIDF4iZk4Tcecjoxuru\n"
|
||||
"fIWu9dMtyDVV+HT2X4cNEnO1/oS3kJII9wJBAJkdwDwiqz4lV6o/yFZ4zAoc8dsu\n"
|
||||
"CoZXYMq5SYox5tTQit928OHLn4mVgqBjhPsiEVnyx0+zUZpmE2ZemHm5nxECQHfE\n"
|
||||
"FBVzVYRP6+eil7E3XRrZKqc3qiLunxpkA4RxYebtKnaxwLmdOI1VB9InEQ8JcNmT\n"
|
||||
"BUkOzJx6p+mJ3XJfchkCQQDWmbMYYJajsjlS4YpdUUj7cBSotA6vtkNVHFr0/ak/\n"
|
||||
"S+tLkMNuruaInWizK+BKYTIJLlQDf5u5NTrw41vye5Hv\n"
|
||||
"-----END RSA PRIVATE KEY-----\n";
|
||||
|
||||
/* Expired:
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 6 (0x6)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: C=JP, ST=Tokyo, L=Koganei, O=WIDE, OU=AAA WG, CN=chavroux.cowaddict.org/emailAddress=sdecugis@nict.go.jp
|
||||
Validity
|
||||
Not Before: Oct 27 04:06:35 2009 GMT
|
||||
Not After : Oct 28 04:06:35 2009 GMT
|
||||
Subject: C=JP, ST=Tokyo, L=Koganei, O=WIDE, OU=AAA WG, CN=expired.test/emailAddress=expired@test
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
RSA Public Key: (1024 bit)
|
||||
Modulus (1024 bit):
|
||||
00:e3:17:15:54:85:dc:cf:c7:a0:32:4a:49:7d:55:
|
||||
75:9b:29:15:db:7e:87:17:d9:0e:65:44:53:d7:19:
|
||||
37:27:c7:c6:fe:c6:dc:72:2b:dc:86:1a:ff:24:6c:
|
||||
63:3f:75:9c:0a:14:e1:70:06:79:d4:b9:26:d4:68:
|
||||
4c:28:38:ba:34:60:56:02:3d:94:55:4a:1f:4e:5a:
|
||||
f0:a5:71:4c:3e:71:69:39:ad:bc:aa:55:35:fb:73:
|
||||
5b:5f:6c:30:71:8e:8a:b6:a5:06:cc:ee:dd:29:c7:
|
||||
52:0d:a7:9c:0f:a1:ba:52:11:e2:1b:b9:74:6b:08:
|
||||
87:11:d2:ec:a9:ac:63:63:4f
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
Netscape Comment:
|
||||
OpenSSL Generated Certificate
|
||||
X509v3 Subject Key Identifier:
|
||||
1C:AF:66:42:5B:AD:AA:A5:9B:D9:AE:3A:C1:5A:AC:2F:CC:CE:22:6C
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:92:AA:55:9F:B3:77:82:68:89:ED:7E:73:43:66:E4:8B:EE:EA:BF:85
|
||||
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
60:8f:55:55:59:82:0f:64:cb:b8:11:c8:44:ce:bf:69:07:0d:
|
||||
be:c2:34:be:42:6a:78:15:39:9f:be:8a:17:d6:43:42:c9:7c:
|
||||
f1:6d:5d:aa:c3:1b:4d:b0:f0:b6:73:46:2a:87:cd:55:56:a3:
|
||||
6d:cc:de:a8:28:6a:53:85:9e:e5:68:b7:3c:f5:72:13:7b:d0:
|
||||
21:f2:91:49:35:e0:37:1e:28:19:d5:1b:cc:e1:32:1e:7f:b0:
|
||||
86:df:43:a4:47:0f:29:0b:eb:51:60:9a:f5:ca:50:f4:2d:59:
|
||||
cd:fc:50:9d:29:ed:45:98:de:a2:5c:d1:b5:7a:34:ad:7a:73:
|
||||
48:8b:a2:9b:89:8e:4a:2e:2a:04:19:d6:62:6a:0d:f0:96:f2:
|
||||
f0:d0:22:77:3b:7f:b1:2a:f4:3b:17:47:5e:38:07:09:65:ad:
|
||||
1d:ea:46:69:6a:96:b6:6b:3b:5c:cc:6e:30:d7:cb:53:69:59:
|
||||
c2:63:78:2b:03:d4:d4:f7:17:29:99:9a:43:ff:78:0a:af:42:
|
||||
c5:b3:8d:09:38:5b:30:70:28:c1:97:ab:fd:7f:87:9a:ec:f2:
|
||||
97:44:ff:f5:b9:41:30:d1:c6:32:98:69:34:c4:39:30:6f:e2:
|
||||
d3:b2:70:97:66:ee:41:f5:ae:0f:09:f0:ed:60:96:67:a9:8a:
|
||||
cd:d6:95:f2
|
||||
*/
|
||||
/*
|
||||
static char expired_cert_data[]="-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIDizCCAnOgAwIBAgIBBjANBgkqhkiG9w0BAQUFADCBlDELMAkGA1UEBhMCSlAx\n"
|
||||
"DjAMBgNVBAgMBVRva3lvMRAwDgYDVQQHDAdLb2dhbmVpMQ0wCwYDVQQKDARXSURF\n"
|
||||
"MQ8wDQYDVQQLDAZBQUEgV0cxHzAdBgNVBAMMFmNoYXZyb3V4LmNvd2FkZGljdC5v\n"
|
||||
"cmcxIjAgBgkqhkiG9w0BCQEWE3NkZWN1Z2lzQG5pY3QuZ28uanAwHhcNMDkxMDI3\n"
|
||||
"MDQwNjM1WhcNMDkxMDI4MDQwNjM1WjCBgzELMAkGA1UEBhMCSlAxDjAMBgNVBAgM\n"
|
||||
"BVRva3lvMRAwDgYDVQQHDAdLb2dhbmVpMQ0wCwYDVQQKDARXSURFMQ8wDQYDVQQL\n"
|
||||
"DAZBQUEgV0cxFTATBgNVBAMMDGV4cGlyZWQudGVzdDEbMBkGCSqGSIb3DQEJARYM\n"
|
||||
"ZXhwaXJlZEB0ZXN0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjFxVUhdzP\n"
|
||||
"x6AySkl9VXWbKRXbfocX2Q5lRFPXGTcnx8b+xtxyK9yGGv8kbGM/dZwKFOFwBnnU\n"
|
||||
"uSbUaEwoOLo0YFYCPZRVSh9OWvClcUw+cWk5rbyqVTX7c1tfbDBxjoq2pQbM7t0p\n"
|
||||
"x1INp5wPobpSEeIbuXRrCIcR0uyprGNjTwIDAQABo3sweTAJBgNVHRMEAjAAMCwG\n"
|
||||
"CWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNV\n"
|
||||
"HQ4EFgQUHK9mQlutqqWb2a46wVqsL8zOImwwHwYDVR0jBBgwFoAUkqpVn7N3gmiJ\n"
|
||||
"7X5zQ2bki+7qv4UwDQYJKoZIhvcNAQEFBQADggEBAGCPVVVZgg9ky7gRyETOv2kH\n"
|
||||
"Db7CNL5CangVOZ++ihfWQ0LJfPFtXarDG02w8LZzRiqHzVVWo23M3qgoalOFnuVo\n"
|
||||
"tzz1chN70CHykUk14DceKBnVG8zhMh5/sIbfQ6RHDykL61FgmvXKUPQtWc38UJ0p\n"
|
||||
"7UWY3qJc0bV6NK16c0iLopuJjkouKgQZ1mJqDfCW8vDQInc7f7Eq9DsXR144Bwll\n"
|
||||
"rR3qRmlqlrZrO1zMbjDXy1NpWcJjeCsD1NT3FymZmkP/eAqvQsWzjQk4WzBwKMGX\n"
|
||||
"q/1/h5rs8pdE//W5QTDRxjKYaTTEOTBv4tOycJdm7kH1rg8J8O1glmepis3WlfI=\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
static char expired_priv_data[]="-----BEGIN RSA PRIVATE KEY-----\n"
|
||||
"MIICXgIBAAKBgQDjFxVUhdzPx6AySkl9VXWbKRXbfocX2Q5lRFPXGTcnx8b+xtxy\n"
|
||||
"K9yGGv8kbGM/dZwKFOFwBnnUuSbUaEwoOLo0YFYCPZRVSh9OWvClcUw+cWk5rbyq\n"
|
||||
"VTX7c1tfbDBxjoq2pQbM7t0px1INp5wPobpSEeIbuXRrCIcR0uyprGNjTwIDAQAB\n"
|
||||
"AoGASwPoDui9XYHTIGm7xwRA+kVjLAOq+qy//aHJlEeHGcP7r1PfpHNqwH4QhGat\n"
|
||||
"jlv6dLYbFld9TVDwS8A8UBkVIPLWnCysd5tF2A4C5akx6ouW6HliW/JheYrgl8AV\n"
|
||||
"PVeR3bm91UbnpC0ABVlw87jp1Ovyr60Suo4jsoJz+CyTa2ECQQD0LJWpnwn1jIlR\n"
|
||||
"DGkLi7F3E70JJcdhTWzBjGFD+Na+/2ZO0MKLhK+O1WUkKa0oi+e5P1JOnGIpTI8c\n"
|
||||
"BJOO415RAkEA7hauapYuqGI/auSPH8/nFB5z1G94RTxo2a5THKcG5MqS/8N3ubFj\n"
|
||||
"i2PPS0lEYVjqoHEsZUsMnDmXp6KDKMAfnwJBAIp+T1UqM8fmsmwaEerOjRXxSCNM\n"
|
||||
"Hk5+T9Vn/jNDjOpAipLhrbbcx4bIWtmsGd8Jm6Fi3RhhcvvhxLorjlZZeEECQQCf\n"
|
||||
"IaPD88sNmlUewdLzhUbCiLQMadCuHflKfRxpyy1tYAQuVFxCTdDlynkzra25ju+K\n"
|
||||
"+vmcXjP4evnk/lbBtt+rAkEAgOr4Apgs3nMppngPV5yFx0NDqH2n8PlEAM1Il4Qs\n"
|
||||
"IuuK18v0KwlUGAfEEmCiNh1e1qkLmD0CnI2QjYAjcLQUhw==\n"
|
||||
"-----END RSA PRIVATE KEY-----\n";
|
||||
*/
|
||||
|
||||
/* Unknown CA certificate :
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 1 (0x1)
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
Issuer: C=JP, ST=Tokyo, L=Koganei, O=WIDE, OU=AAA WG, CN=chavroux.cowaddict.org/emailAddress=sdecugis@nict.go.jp
|
||||
Validity
|
||||
Not Before: Oct 28 08:04:40 2009 GMT
|
||||
Not After : Oct 28 08:04:40 2010 GMT
|
||||
Subject: C=JP, ST=Tokyo, L=Koganei, O=WIDE, OU=AAA WG, CN=unknown.cs/emailAddress=unknown@ca
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
RSA Public Key: (1024 bit)
|
||||
Modulus (1024 bit):
|
||||
00:e6:3a:d5:8a:14:c8:15:d0:f0:5c:03:c3:af:33:
|
||||
51:2c:17:b7:65:ac:45:e8:48:2d:ae:70:fd:7c:79:
|
||||
3a:c7:80:c8:50:53:d0:19:d8:3a:26:a8:16:4d:4c:
|
||||
04:17:09:df:69:9b:59:2b:89:c8:e0:60:bb:1d:37:
|
||||
82:d2:3f:17:39:c9:8f:5d:76:e1:0f:6e:08:9a:8f:
|
||||
16:4a:ea:83:86:f9:bd:15:14:56:68:87:79:05:f9:
|
||||
5f:66:11:bd:22:46:26:64:be:57:16:51:66:41:50:
|
||||
ac:f2:b1:ca:d0:38:11:4b:4c:b2:ee:25:36:6e:d3:
|
||||
b9:63:72:c4:84:82:1c:2b:27
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
Netscape Comment:
|
||||
OpenSSL Generated Certificate
|
||||
X509v3 Subject Key Identifier:
|
||||
BA:5A:9D:D2:B0:4B:72:D6:1F:00:11:0B:B5:7B:59:DF:08:38:81:BE
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:52:C5:A4:63:B8:DB:AC:F2:92:34:2F:72:56:71:C8:11:8E:76:E6:DF
|
||||
|
||||
Signature Algorithm: sha1WithRSAEncryption
|
||||
90:8f:3b:bd:e3:a1:ca:6a:92:a6:fd:f0:64:ae:46:83:32:35:
|
||||
61:80:57:8b:30:12:70:02:e1:51:d9:87:c8:af:d9:4b:b9:6d:
|
||||
bf:ab:86:5f:19:1f:dc:af:84:67:bf:3c:bf:33:f3:7c:c6:81:
|
||||
7b:e4:e9:26:1d:bc:d6:8c:ab:72:94:7f:85:33:95:d9:24:ec:
|
||||
fd:7b:d2:fd:50:3e:e5:61:4f:75:51:ae:c6:4a:ec:df:cf:aa:
|
||||
73:a5:08:f7:f3:9a:40:66:48:f0:8e:9b:43:b1:30:f3:e3:c8:
|
||||
36:3f:68:36:6a:1c:aa:16:40:49:b4:73:9a:71:f1:17:6c:0b:
|
||||
d3:e1:a7:b7:40:de:2c:3c:36:7c:d4:dd:d6:94:c9:d7:5f:f5:
|
||||
ae:35:56:e8:cc:65:9c:bb:3d:e8:7a:ca:0e:ed:78:03:41:cb:
|
||||
fd:80:81:de:f9:de:b2:14:4b:81:24:36:de:29:c1:06:11:86:
|
||||
8c:a9:b0:0c:c7:57:cf:79:a7:3a:84:0c:27:dc:86:6d:cb:44:
|
||||
2d:26:dc:7e:fb:17:d6:b2:3d:31:03:d3:f1:ab:5d:91:5d:94:
|
||||
e4:94:88:70:96:b3:7c:0f:15:fe:c8:c6:4d:99:37:ab:09:0c:
|
||||
da:ba:b6:0e:fa:5e:bb:4b:ce:04:21:06:09:a9:2c:27:86:76:
|
||||
cc:ee:73:6f
|
||||
*/
|
||||
/*
|
||||
static char notrust_ca_data[] = "-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIEqjCCA5KgAwIBAgIJAP3UMghSlH9PMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD\n"
|
||||
"VQQGEwJKUDEOMAwGA1UECAwFVG9reW8xEDAOBgNVBAcMB0tvZ2FuZWkxDTALBgNV\n"
|
||||
"BAoMBFdJREUxDzANBgNVBAsMBkFBQSBXRzEfMB0GA1UEAwwWY2hhdnJvdXguY293\n"
|
||||
"YWRkaWN0Lm9yZzEiMCAGCSqGSIb3DQEJARYTc2RlY3VnaXNAbmljdC5nby5qcDAe\n"
|
||||
"Fw0wOTEwMjgwODAzNDRaFw0xOTEwMjYwODAzNDRaMIGUMQswCQYDVQQGEwJKUDEO\n"
|
||||
"MAwGA1UECAwFVG9reW8xEDAOBgNVBAcMB0tvZ2FuZWkxDTALBgNVBAoMBFdJREUx\n"
|
||||
"DzANBgNVBAsMBkFBQSBXRzEfMB0GA1UEAwwWY2hhdnJvdXguY293YWRkaWN0Lm9y\n"
|
||||
"ZzEiMCAGCSqGSIb3DQEJARYTc2RlY3VnaXNAbmljdC5nby5qcDCCASIwDQYJKoZI\n"
|
||||
"hvcNAQEBBQADggEPADCCAQoCggEBALKW9iSUggF5mbvYe1Xk128Csfiijx+fwH5y\n"
|
||||
"ZqWrHNt0YG/tZSwyCDMWBLXTeuYsntg5y0mcpsrN8v02tvrPiCzDfRPyz3mG68us\n"
|
||||
"DPEEgQ1kqL2Gsti2DUcsdyZcDM+4rgsWRivgOTVyoNimv5f+xgmPYoElkgelLwZK\n"
|
||||
"WxGt1VCebOxP3qZA3hSHWE1hJgL4svful7RD1PbwPzidxJKITyAiJoPKWQA9cjSa\n"
|
||||
"gVzRQ7S4vmYALJn7xe+dMFRcfAK8RMv7/gJF6Rw7zufW0DIZK98KZs6aL0lmMPVk\n"
|
||||
"f31N2uvndf+cjy0n4luwEoXY+TeJZY205lbwHrzR0rH75FSm0RsCAwEAAaOB/DCB\n"
|
||||
"+TAdBgNVHQ4EFgQUUsWkY7jbrPKSNC9yVnHIEY525t8wgckGA1UdIwSBwTCBvoAU\n"
|
||||
"UsWkY7jbrPKSNC9yVnHIEY525t+hgZqkgZcwgZQxCzAJBgNVBAYTAkpQMQ4wDAYD\n"
|
||||
"VQQIDAVUb2t5bzEQMA4GA1UEBwwHS29nYW5laTENMAsGA1UECgwEV0lERTEPMA0G\n"
|
||||
"A1UECwwGQUFBIFdHMR8wHQYDVQQDDBZjaGF2cm91eC5jb3dhZGRpY3Qub3JnMSIw\n"
|
||||
"IAYJKoZIhvcNAQkBFhNzZGVjdWdpc0BuaWN0LmdvLmpwggkA/dQyCFKUf08wDAYD\n"
|
||||
"VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEACANo6IR3OQlQaXHJaprVVDvl\n"
|
||||
"oMJC0FRbVCK503sbmWTJL98UqxRdsTZNIL07gXlK0oUKyiNijIXiLG8d5IlUrDxF\n"
|
||||
"H/Vsu6s8k3/PpAUVeiO2oygWqvU5NGvt0jg54MrOJKhYYPWrzbmHty+cAXyoNzOR\n"
|
||||
"+W5RX6HRQgxvZWQq2Ok46VX622R1nNjFmCBYT7I7/gWG+hkbIAoH6d9sULLjpC+B\n"
|
||||
"bI+L/N7ac9/Og8pGIgpUI60Gn5zO93+E+Nhg+1BlcDHGnQD6vFNs8LYp5CCX/Zj1\n"
|
||||
"tWFVXZnx58odaU3M4t9/ZQnkZdx9YJIroETbN0PoqlnSagBjgUvbWwn4YCotCA==\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
static char notrust_cert_data[]="-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIDhjCCAm6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBlDELMAkGA1UEBhMCSlAx\n"
|
||||
"DjAMBgNVBAgMBVRva3lvMRAwDgYDVQQHDAdLb2dhbmVpMQ0wCwYDVQQKDARXSURF\n"
|
||||
"MQ8wDQYDVQQLDAZBQUEgV0cxHzAdBgNVBAMMFmNoYXZyb3V4LmNvd2FkZGljdC5v\n"
|
||||
"cmcxIjAgBgkqhkiG9w0BCQEWE3NkZWN1Z2lzQG5pY3QuZ28uanAwHhcNMDkxMDI4\n"
|
||||
"MDgwNDQwWhcNMTAxMDI4MDgwNDQwWjB/MQswCQYDVQQGEwJKUDEOMAwGA1UECAwF\n"
|
||||
"VG9reW8xEDAOBgNVBAcMB0tvZ2FuZWkxDTALBgNVBAoMBFdJREUxDzANBgNVBAsM\n"
|
||||
"BkFBQSBXRzETMBEGA1UEAwwKdW5rbm93bi5jczEZMBcGCSqGSIb3DQEJARYKdW5r\n"
|
||||
"bm93bkBjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5jrVihTIFdDwXAPD\n"
|
||||
"rzNRLBe3ZaxF6EgtrnD9fHk6x4DIUFPQGdg6JqgWTUwEFwnfaZtZK4nI4GC7HTeC\n"
|
||||
"0j8XOcmPXXbhD24Imo8WSuqDhvm9FRRWaId5BflfZhG9IkYmZL5XFlFmQVCs8rHK\n"
|
||||
"0DgRS0yy7iU2btO5Y3LEhIIcKycCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgB\n"
|
||||
"hvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYE\n"
|
||||
"FLpandKwS3LWHwARC7V7Wd8IOIG+MB8GA1UdIwQYMBaAFFLFpGO426zykjQvclZx\n"
|
||||
"yBGOdubfMA0GCSqGSIb3DQEBBQUAA4IBAQCQjzu946HKapKm/fBkrkaDMjVhgFeL\n"
|
||||
"MBJwAuFR2YfIr9lLuW2/q4ZfGR/cr4Rnvzy/M/N8xoF75OkmHbzWjKtylH+FM5XZ\n"
|
||||
"JOz9e9L9UD7lYU91Ua7GSuzfz6pzpQj385pAZkjwjptDsTDz48g2P2g2ahyqFkBJ\n"
|
||||
"tHOacfEXbAvT4ae3QN4sPDZ81N3WlMnXX/WuNVbozGWcuz3oesoO7XgDQcv9gIHe\n"
|
||||
"+d6yFEuBJDbeKcEGEYaMqbAMx1fPeac6hAwn3IZty0QtJtx++xfWsj0xA9Pxq12R\n"
|
||||
"XZTklIhwlrN8DxX+yMZNmTerCQzaurYO+l67S84EIQYJqSwnhnbM7nNv\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
static char notrust_priv_data[]="-----BEGIN RSA PRIVATE KEY-----\n"
|
||||
"MIICXQIBAAKBgQDmOtWKFMgV0PBcA8OvM1EsF7dlrEXoSC2ucP18eTrHgMhQU9AZ\n"
|
||||
"2DomqBZNTAQXCd9pm1kricjgYLsdN4LSPxc5yY9dduEPbgiajxZK6oOG+b0VFFZo\n"
|
||||
"h3kF+V9mEb0iRiZkvlcWUWZBUKzyscrQOBFLTLLuJTZu07ljcsSEghwrJwIDAQAB\n"
|
||||
"AoGAeRec1SGVE5Rvt5XrSK0vFofq2DlCE6hTDpszWFLTDbe4pDdRDybhfw+Nm15O\n"
|
||||
"EGgK8BrbTcEMvKdkAzv9POQeLDE8JImgesHZFxN3jnkK+b762BGRDt57DzvMJsfj\n"
|
||||
"1LBle+UBnZB1CvjrINvu+tNMVPlUpjIstbpMq0D+s01+ijECQQD8MHTv/M+Uc86u\n"
|
||||
"1SFywgs+eQPQ8g0OoTLxzqo6YhW8FtwLjoRCZx2TNQS5gYBuQrixd/yE0Spfv9aS\n"
|
||||
"UtlAaOc1AkEA6bVufggHVHcgiWqS8CHzb6g/GRxQixVshOsoVLMkCSz04zlwIfXF\n"
|
||||
"c03hh5RJVv7jmuBmhHbayujMgvinw75oawJAQb9oXUDt5Wgj1FTgeYi5YbovEoRo\n"
|
||||
"fw3ruDsHCl2UCQt0ptarCJzVixFhf/ORRi3C9RGxFfdqMrhS+qb62N4AmQJBALYU\n"
|
||||
"T1BLiwJoiWXmLTJ/EP0V9Irov2uMtm5cE6DhrJqlduksz8r1gu7RZ3tMsVLg5Iy+\n"
|
||||
"dcCQJOffNa54caQUTZ8CQQDTs/70Nr6F6ktrtmtU/S7lIitpQJCu9u/SPyBYPmFZ\n"
|
||||
"9Axy6Ee66Php+eWDNP4Ln4axrapD0732wD8DcmGDVHij\n"
|
||||
"-----END RSA PRIVATE KEY-----\n";
|
||||
*/
|
||||
|
||||
/* Diffie-Hellman parameters, generated with GNUTLS certtool:
|
||||
certtool --generate-dh-params
|
||||
Generator: 06
|
||||
|
||||
Prime: ea:c3:75:0b:32:cf:d9:17:98:5c:da:d1
|
||||
e0:1d:b9:7c:be:29:60:b0:6f:68:a9:f6
|
||||
8d:75:05:59:69:04:ae:39:7c:2b:74:04
|
||||
3c:e2:da:28:8a:9b:93:aa:67:05:a7:3e
|
||||
06:3e:0d:31:63:88:55:ad:5a:bd:41:22
|
||||
b7:58:a7:45:b3:d5:03:ad:de:3c:8d:69
|
||||
42:bf:84:3d:c1:90:e7:39:6a:4b:87:01
|
||||
19:e5:f3:a4:e5:8e:e2:45:d5:0c:6b:17
|
||||
22:2b:2e:50:83:91:0c:5b:82:fc:72:27
|
||||
49:3b:9f:29:11:53:c7:90:b8:8d:87:73
|
||||
1a:7b:05:ab:cb:30:59:16:71:30:60:1b
|
||||
4c:80:15:3a:a2:d3:47:b7:4a:61:de:64
|
||||
7e:79:de:88:53:b7:7a:c6:a2:9a:bb:55
|
||||
40:2d:7a:71:c7:41:b5:29:df:d7:5c:fb
|
||||
42:e4:d8:5e:0b:99:d3:3c:93:0f:33:51
|
||||
8b:f4:60:e4:c5:b5:58:21:c0:51:c4:43
|
||||
25:7c:37:fe:5c:d3:62:6c:2a:af:a7:2a
|
||||
82:d5:d3:e2:bb:5d:ad:84:15:f6:78:d9
|
||||
d5:a8:f7:f0:48:5c:8d:e0:3d:04:ac:cf
|
||||
aa:34:3f:5d:f2:0d:3d:ee:ec:b8:d8:e8
|
||||
ad:dc:d3:40:59:a0:fd:45:62:47:63:c0
|
||||
bd:f5:df:8b
|
||||
*/
|
||||
static char dh_params_data[] = "-----BEGIN DH PARAMETERS-----\n"
|
||||
"MIIBCAKCAQEA6sN1CzLP2ReYXNrR4B25fL4pYLBvaKn2jXUFWWkErjl8K3QEPOLa\n"
|
||||
"KIqbk6pnBac+Bj4NMWOIVa1avUEit1inRbPVA63ePI1pQr+EPcGQ5zlqS4cBGeXz\n"
|
||||
"pOWO4kXVDGsXIisuUIORDFuC/HInSTufKRFTx5C4jYdzGnsFq8swWRZxMGAbTIAV\n"
|
||||
"OqLTR7dKYd5kfnneiFO3esaimrtVQC16ccdBtSnf11z7QuTYXguZ0zyTDzNRi/Rg\n"
|
||||
"5MW1WCHAUcRDJXw3/lzTYmwqr6cqgtXT4rtdrYQV9njZ1aj38EhcjeA9BKzPqjQ/\n"
|
||||
"XfINPe7suNjordzTQFmg/UViR2PAvfXfiwIBBg==\n"
|
||||
"-----END DH PARAMETERS-----\n";
|
||||
|
||||
|
||||
|
||||
int fddparse(struct fd_config * conf)
|
||||
{
|
||||
return shParse(conf);
|
||||
|
||||
#if 0
|
||||
/* sctp */
|
||||
conf->cnf_sec_data.tls_disabled = 1;
|
||||
conf->cnf_port_tls = 0; // DIAMETER_SECURE_PORT;
|
||||
conf->cnf_sctp_str = 10;
|
||||
conf->cnf_flags.no_fwd = 1;
|
||||
conf->cnf_flags.no_ip4 = 0;
|
||||
conf->cnf_flags.no_ip6 = 0;
|
||||
conf->cnf_flags.no_tcp = 1;
|
||||
conf->cnf_flags.no_sctp = 0;
|
||||
conf->cnf_flags.pr_tcp = 0;
|
||||
conf->cnf_flags.tls_alg = 0;
|
||||
|
||||
/* tcp */
|
||||
conf->cnf_sec_data.tls_disabled = 0;
|
||||
conf->cnf_port_tls = 0;
|
||||
conf->cnf_sctp_str = 10;
|
||||
conf->cnf_flags.no_fwd = 1;
|
||||
conf->cnf_flags.no_ip4 = 0;
|
||||
conf->cnf_flags.no_ip6 = 0;
|
||||
conf->cnf_flags.no_tcp = 0;
|
||||
conf->cnf_flags.no_sctp = 1;
|
||||
conf->cnf_flags.pr_tcp = 1;
|
||||
conf->cnf_flags.tls_alg = 0;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
gnutls_datum_t ca = { (uint8_t *)ca_data, sizeof(ca_data) };
|
||||
gnutls_datum_t server_cert = { (uint8_t *)server_cert_data, sizeof(server_cert_data) };
|
||||
gnutls_datum_t server_priv = { (uint8_t *)server_priv_data, sizeof(server_priv_data) };
|
||||
// gnutls_datum_t client_cert = { (uint8_t *)client_cert_data, sizeof(client_cert_data) };
|
||||
// gnutls_datum_t client_priv = { (uint8_t *)client_priv_data, sizeof(client_priv_data) };
|
||||
// gnutls_datum_t expired_cert = { (uint8_t *)expired_cert_data, sizeof(expired_cert_data) };
|
||||
// gnutls_datum_t expired_priv = { (uint8_t *)expired_priv_data, sizeof(expired_priv_data) };
|
||||
// gnutls_datum_t notrust_ca = { (uint8_t *)notrust_ca_data, sizeof(notrust_ca_data) };
|
||||
// gnutls_datum_t notrust_cert = { (uint8_t *)notrust_cert_data, sizeof(notrust_cert_data) };
|
||||
// gnutls_datum_t notrust_priv = { (uint8_t *)notrust_priv_data, sizeof(notrust_priv_data) };
|
||||
gnutls_datum_t dh_params = { (uint8_t *)dh_params_data, sizeof(dh_params_data) };
|
||||
|
||||
int ret;
|
||||
|
||||
/* Set the CA parameter in the config */
|
||||
CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_trust_mem( conf->cnf_sec_data.credentials,
|
||||
&ca,
|
||||
GNUTLS_X509_FMT_PEM), );
|
||||
assert( 1 == ret );
|
||||
|
||||
#ifdef GNUTLS_VERSION_300
|
||||
{
|
||||
/* We import these CA in the trust list */
|
||||
gnutls_x509_crt_t * calist;
|
||||
unsigned int cacount = 0;
|
||||
|
||||
CHECK_GNUTLS_DO( ret = gnutls_x509_crt_list_import2(&calist, &cacount, &ca, GNUTLS_X509_FMT_PEM,
|
||||
GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED), );
|
||||
CHECK( 1, cacount );
|
||||
|
||||
CHECK_GNUTLS_DO( ret = gnutls_x509_trust_list_add_cas (conf->cnf_sec_data.trustlist, calist, cacount, 0), );
|
||||
CHECK( 1, ret );
|
||||
}
|
||||
|
||||
/* Use certificate verification during the handshake */
|
||||
gnutls_certificate_set_verify_function (conf->cnf_sec_data.credentials, fd_tls_verify_credentials_2);
|
||||
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
|
||||
|
||||
/* Set the server credentials (in config) */
|
||||
CHECK_GNUTLS_DO( ret = gnutls_certificate_set_x509_key_mem( conf->cnf_sec_data.credentials,
|
||||
&server_cert,
|
||||
&server_priv,
|
||||
GNUTLS_X509_FMT_PEM), );
|
||||
assert( GNUTLS_E_SUCCESS == ret );
|
||||
|
||||
/* Set the default priority */
|
||||
CHECK_GNUTLS_DO( ret = gnutls_priority_init( &conf->cnf_sec_data.prio_cache, "NORMAL"/*GNUTLS_DEFAULT_PRIORITY*/, NULL), );
|
||||
assert( GNUTLS_E_SUCCESS == ret );
|
||||
|
||||
/* Set default DH params */
|
||||
CHECK_GNUTLS_DO( ret = gnutls_dh_params_import_pkcs3( conf->cnf_sec_data.dh_cache, &dh_params, GNUTLS_X509_FMT_PEM), );
|
||||
assert( GNUTLS_E_SUCCESS == ret );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fd_sh_avp_search_avp ( struct avp * groupedavp, struct dict_object * what, struct avp ** avp )
|
||||
{
|
||||
struct avp * nextavp;
|
||||
struct avp_hdr * nextavphdr;
|
||||
struct dict_avp_data dictdata;
|
||||
|
||||
|
||||
TRACE_ENTRY("%p %p %p", groupedavp, what, avp);
|
||||
|
||||
CHECK_FCT( fd_dict_getval(what, &dictdata) );
|
||||
|
||||
// Loop only in the group AVP
|
||||
CHECK_FCT( fd_msg_browse(groupedavp, MSG_BRW_FIRST_CHILD, (void *)&nextavp, NULL) );
|
||||
CHECK_FCT( fd_msg_avp_hdr( nextavp, &nextavphdr ) );
|
||||
|
||||
while (nextavphdr) {
|
||||
|
||||
if ( (nextavphdr->avp_code == dictdata.avp_code) && (nextavphdr->avp_vendor == dictdata.avp_vendor) ) // always 0 if no Vendor flag
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise move to next AVP in the grouped AVP
|
||||
CHECK_FCT( fd_msg_browse(nextavp, MSG_BRW_NEXT, (void *)&nextavp, NULL) );
|
||||
|
||||
if(nextavp!=NULL)
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_hdr( nextavp, &nextavphdr ) );
|
||||
}
|
||||
else
|
||||
nextavphdr=NULL;
|
||||
}
|
||||
if (avp)
|
||||
*avp = nextavp;
|
||||
|
||||
if (avp && nextavp) {
|
||||
struct dictionary * dict;
|
||||
CHECK_FCT( fd_dict_getdict( what, &dict) );
|
||||
CHECK_FCT_DO( fd_msg_parse_dict( nextavp, dict, NULL ), );
|
||||
}
|
||||
|
||||
if (avp || nextavp)
|
||||
return 0;
|
||||
else
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
|
||||
EXTENSION_ENTRY("test_app", ta_entry);
|
||||
538
plat/diameter/extensions/sh_app/sh_app.h
Normal file
538
plat/diameter/extensions/sh_app/sh_app.h
Normal file
@@ -0,0 +1,538 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/* Header file for the app_test extension.
|
||||
*
|
||||
* This extension provides a way to send configurable messages on the network
|
||||
*
|
||||
* See the app_test.conf.sample file for the format of the configuration file.
|
||||
*/
|
||||
#ifndef __SH_APP_H__
|
||||
#define __SH_APP_H__
|
||||
|
||||
#include "extension.h"
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
#define SH_VND_ID 10415
|
||||
#define SH_APP_ID_OLD 16777217
|
||||
#define SH_APP_ID 4
|
||||
|
||||
#define HW_VND_ID 2011
|
||||
|
||||
/* Mode for the extension */
|
||||
#define MODE_SERV 0x1
|
||||
#define MODE_CLI 0x2
|
||||
#define MODE_BENCH 0x4
|
||||
|
||||
|
||||
|
||||
#ifndef TEST_APP_DEFAULT_SIGNAL
|
||||
#define TEST_APP_DEFAULT_SIGNAL SIGUSR1
|
||||
#endif /* TEST_APP_DEFAULT_SIGNAL */
|
||||
|
||||
#if 0
|
||||
/* encode avp */
|
||||
#define SEARCH_AVP_OLD_(name, vendor_id, retval) \
|
||||
__avp.avp_code = 0; \
|
||||
__avp.avp_name = name; \
|
||||
__avp.avp_vendor = vendor_id; \
|
||||
LOG_D("SEARCH_AVP_ avpName:%s avpVendorID:%d", name, SH_VND_ID); \
|
||||
CHECK_FCT_DO( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &__avp, retval, ENOENT), goto out )
|
||||
#endif
|
||||
#define SEARCH_AVP_(name, vendor_id, retval) \
|
||||
{ struct dict_avp_request tmp_avp;\
|
||||
tmp_avp.avp_code = 0; \
|
||||
tmp_avp.avp_name = name; \
|
||||
tmp_avp.avp_vendor = vendor_id; \
|
||||
LOG_D("SEARCH_AVP_ avpName:%s avpVendorID:%d", name, SH_VND_ID); \
|
||||
CHECK_FCT_DO( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &tmp_avp, retval, ENOENT), goto out ); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define EN_GRPAVP_U32(udr_search_name, vendor_id, udr, u32_val) \
|
||||
{ \
|
||||
SEARCH_AVP_(udr_search_name, vendor_id, &udr); \
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( udr, 0, &avp ), goto out ); \
|
||||
val.u32 = u32_val; \
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); \
|
||||
CHECK_FCT_DO( fd_msg_avp_add( grpavp, MSG_BRW_LAST_CHILD, avp ), goto out ); \
|
||||
}
|
||||
#define EN_GRPAVP_U32_(udr_search_name, vendor_id, udr, u32_val, grpavp) \
|
||||
{ \
|
||||
SEARCH_AVP_(udr_search_name, vendor_id, &udr); \
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( udr, 0, &avp ), goto out ); \
|
||||
val.u32 = u32_val; \
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); \
|
||||
CHECK_FCT_DO( fd_msg_avp_add( grpavp, MSG_BRW_LAST_CHILD, avp ), goto out ); \
|
||||
}
|
||||
#define EN_GRPAVP_U64(udr_search_name, vendor_id, udr, u64_val) \
|
||||
{ \
|
||||
SEARCH_AVP_(udr_search_name, vendor_id, &udr); \
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( udr, 0, &avp ), goto out ); \
|
||||
val.u64 = u64_val; \
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); \
|
||||
CHECK_FCT_DO( fd_msg_avp_add( grpavp, MSG_BRW_LAST_CHILD, avp ), goto out ); \
|
||||
}
|
||||
|
||||
#define EN_GRPAVP_U64_(udr_search_name, vendor_id, udr, u64_val, grpavp) \
|
||||
{ \
|
||||
SEARCH_AVP_(udr_search_name, vendor_id, &udr); \
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( udr, 0, &avp ), goto out ); \
|
||||
val.u64 = u64_val; \
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); \
|
||||
CHECK_FCT_DO( fd_msg_avp_add( grpavp, MSG_BRW_LAST_CHILD, avp ), goto out ); \
|
||||
}
|
||||
#define EN_GRPAVP_STR(udr_search_name, vendor_id, udr, str, grpavp) \
|
||||
{ \
|
||||
SEARCH_AVP_(udr_search_name, vendor_id, &udr); \
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( udr, 0, &avp ), goto out ); \
|
||||
val.os.data = (uint8_t*)(str); \
|
||||
val.os.len = strlen(str); \
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); \
|
||||
CHECK_FCT_DO( fd_msg_avp_add( grpavp, MSG_BRW_LAST_CHILD, avp ), goto out ); \
|
||||
}
|
||||
#define EN_GRPAVP_STR_BCD(udr_search_name, vendor_id, udr, str, str_len, grpavp) \
|
||||
{ \
|
||||
SEARCH_AVP_(udr_search_name, vendor_id, &udr); \
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( udr, 0, &avp ), goto out ); \
|
||||
val.os.data = (uint8_t*)(str); \
|
||||
memcpy(val.os.data, str, str_len);\
|
||||
val.os.len = str_len; \
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); \
|
||||
CHECK_FCT_DO( fd_msg_avp_add( grpavp, MSG_BRW_LAST_CHILD, avp ), goto out ); \
|
||||
}
|
||||
|
||||
#define EN_AVP_U32(udr, u32_val, msg_name, log_info) \
|
||||
{ \
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( udr, 0, &avp ), goto out ); \
|
||||
val.u32 = u32_val; \
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); \
|
||||
CHECK_FCT_DO( fd_msg_avp_add( msg_name, MSG_BRW_LAST_CHILD, avp ), goto out ); \
|
||||
LOG_N("%s\n", log_info); \
|
||||
}
|
||||
|
||||
#define EN_AVP_STR(udr, str, msg_name, log_info) \
|
||||
{ \
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( udr, 0, &avp ) , goto out ); \
|
||||
val.os.data = (unsigned char *)(str); \
|
||||
val.os.len = strlen(str); \
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); \
|
||||
CHECK_FCT_DO( fd_msg_avp_add( msg_name, MSG_BRW_LAST_CHILD, avp ), goto out ); \
|
||||
LOG_N("%s\n", log_info); \
|
||||
}
|
||||
|
||||
#define EN_AVP_BCDSTR(udr, str, tmplen, msg_name, log_info) \
|
||||
{ \
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( udr, 0, &avp ) , goto out ); \
|
||||
val.os.data = (unsigned char *)(str); \
|
||||
val.os.len = tmplen; \
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); \
|
||||
CHECK_FCT_DO( fd_msg_avp_add( msg_name, MSG_BRW_LAST_CHILD, avp ), goto out ); \
|
||||
LOG_N("%s\n", log_info); \
|
||||
}
|
||||
|
||||
/* parse avp */
|
||||
#define PARSE_GRPAVP_U32(grpavp, obj, avp, avphdr, tip, val) \
|
||||
CHECK_FCT( fd_sh_avp_search_avp ( grpavp, obj, &avp) ); \
|
||||
if(avp != NULL) \
|
||||
{ \
|
||||
CHECK_FCT( fd_msg_avp_hdr( avp, &avphdr ) ); \
|
||||
}
|
||||
// LOG_N("fj %s:%d", tip, val);
|
||||
|
||||
#define PARSE_GRPAVP_U64(grpavp, obj, avp, avphdr, tip, val) \
|
||||
CHECK_FCT( fd_sh_avp_search_avp ( grpavp, obj, &avp) ); \
|
||||
if(avp != NULL) \
|
||||
{ \
|
||||
CHECK_FCT( fd_msg_avp_hdr( avp, &avphdr ) ); \
|
||||
}
|
||||
// LOG_N("fj %s:%lu", tip, val);
|
||||
|
||||
|
||||
#define PARSE_GRPAVP_STR(grpavp, obj, avp, avphdr, tip, val) \
|
||||
CHECK_FCT( fd_sh_avp_search_avp ( grpavp, obj, &avp) ); \
|
||||
if(avp != NULL) \
|
||||
{ \
|
||||
CHECK_FCT( fd_msg_avp_hdr( avp, &avphdr ) ); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define PARSE_AVP_U32(msg, obj, avp, avphdr, tip, val) \
|
||||
CHECK_FCT( fd_msg_search_avp ( msg, obj, &avp) ); \
|
||||
if(avp != NULL) \
|
||||
{ \
|
||||
CHECK_FCT( fd_msg_avp_hdr( avp, &avphdr ) ); \
|
||||
}
|
||||
// LOG_N("fj %s:%d", tip, val);
|
||||
|
||||
#define PARSE_AVP_STR(msg, obj, avp, avphdr, tip, val) \
|
||||
CHECK_FCT( fd_msg_search_avp ( msg, obj, &avp) ); \
|
||||
if(avp != NULL) \
|
||||
{ \
|
||||
CHECK_FCT( fd_msg_avp_hdr( avp, &avphdr ) ); \
|
||||
}
|
||||
// LOG_N("fj %s:%s", tip, val);
|
||||
|
||||
|
||||
|
||||
/* udr avp */
|
||||
/*
|
||||
< Session-Id >
|
||||
[ DRMP ]
|
||||
{ Vendor-Specific-Application-Id }
|
||||
{ Auth-Session-State }
|
||||
{ Origin-Host }
|
||||
{ Origin-Realm }
|
||||
[ Destination-Host ]
|
||||
{ Destination-Realm }
|
||||
*[ Supported-Features ]
|
||||
{ User-Identity }
|
||||
[ Wildcarded-Public-Identity ]
|
||||
[ Wildcarded-IMPU ]
|
||||
[ Server-Name ]
|
||||
*[ Service-Indication ]
|
||||
*{ Data-Reference }
|
||||
*[ Identity-Set ]
|
||||
[ Requested-Domain ]
|
||||
[ Current-Location ]
|
||||
*[ DSAI-Tag ]
|
||||
[ Session-Priority ]
|
||||
[ User-Name ]
|
||||
[ Requested-Nodes ]
|
||||
[ Serving-Node-Indication ]
|
||||
[ Pre-paging-Supported ]
|
||||
[ Local-Time-Zone-Indication ]
|
||||
[ UDR-Flags ]
|
||||
[ Call-Reference-Info ]
|
||||
[ OC-Supported-Features ]
|
||||
*[ AVP ]
|
||||
*[ Proxy-Info ]
|
||||
*[ Route-Record ]
|
||||
*/
|
||||
struct sh_udr_msg{
|
||||
struct dict_object * udr_session_id ;
|
||||
struct dict_object * udr_drmp;
|
||||
|
||||
struct dict_object * udr_vendor_specific_application_id;
|
||||
struct dict_object * udr_auth_application_d;
|
||||
struct dict_object * udr_acct_application_id;
|
||||
|
||||
struct dict_object * udr_auth_session_state;
|
||||
struct dict_object * udr_origin_host;
|
||||
struct dict_object * udr_origin_realm;
|
||||
struct dict_object * udr_destination_host;
|
||||
struct dict_object * udr_destination_realm;
|
||||
|
||||
struct dict_object * udr_supported_features;
|
||||
struct dict_object * udr_vendor_id;
|
||||
struct dict_object * udr_feature_list_id;
|
||||
struct dict_object * udr_feature_list;
|
||||
|
||||
struct dict_object * udr_user_identity;
|
||||
struct dict_object * udr_public_identity;
|
||||
struct dict_object * udr_msisdn;
|
||||
|
||||
struct dict_object * udr_wildcarded_public_identity;
|
||||
struct dict_object * udr_wildcarded_impu;
|
||||
struct dict_object * udr_server_name;
|
||||
struct dict_object * udr_service_indication;
|
||||
struct dict_object * udr_data_reference;
|
||||
struct dict_object * udr_identity_set;
|
||||
struct dict_object * udr_requested_domain;
|
||||
struct dict_object * udr_current_location;
|
||||
struct dict_object * udr_dsai_tag;
|
||||
struct dict_object * udr_session_priority;
|
||||
struct dict_object * udr_user_name;
|
||||
struct dict_object * udr_requested_nodes;
|
||||
struct dict_object * udr_serving_node_indication;
|
||||
struct dict_object * udr_pre_paging_supported;
|
||||
struct dict_object * udr_local_time_zone_indication;
|
||||
struct dict_object * udr_udr_flags;
|
||||
|
||||
struct dict_object * udr_call_reference_info;
|
||||
struct dict_object * udr_call_reference_number;
|
||||
struct dict_object * udr_as_number;
|
||||
|
||||
struct dict_object * udr_oc_supported_features;
|
||||
struct dict_object * udr_oc_feature_vector;
|
||||
|
||||
struct dict_object * udr_proxy_info;
|
||||
struct dict_object * udr_route_record;
|
||||
};
|
||||
|
||||
/* uda avp */
|
||||
/*
|
||||
< Session-Id >
|
||||
[ DRMP ]
|
||||
{ Vendor-Specific-Application-Id }
|
||||
[ Result-Code ]
|
||||
[ Experimental-Result ]
|
||||
{ Auth-Session-State }
|
||||
{ Origin-Host }
|
||||
{ Origin-Realm }
|
||||
*[ Supported-Features ]
|
||||
[ Wildcarded-Public-Identity ]
|
||||
[ Wildcarded-IMPU ]
|
||||
[ User-Data ]
|
||||
[ OC-Supported-Features ]
|
||||
[ OC-OLR ]
|
||||
*[ AVP ]
|
||||
*[ Failed-AVP ]
|
||||
*[ Proxy-Info ]
|
||||
*[ Route-Record ]
|
||||
*/
|
||||
struct sh_uda_msg{
|
||||
struct dict_object * uda_session_id;
|
||||
struct dict_object * uda_drmp;
|
||||
|
||||
struct dict_object * uda_vendor_specific_application_id;
|
||||
struct dict_object * uda_vendor_id;
|
||||
struct dict_object * uda_auth_application_d;
|
||||
struct dict_object * uda_acct_application_id;
|
||||
|
||||
struct dict_object * uda_result_code;
|
||||
|
||||
struct dict_object * uda_experimental_result;
|
||||
struct dict_object * uda_experimental_result_code;
|
||||
|
||||
struct dict_object * uda_auth_session_state;
|
||||
struct dict_object * uda_origin_host;
|
||||
struct dict_object * uda_origin_realm;
|
||||
|
||||
struct dict_object * uda_supported_features;
|
||||
struct dict_object * uda_feature_list_id;
|
||||
struct dict_object * uda_feature_list;
|
||||
|
||||
struct dict_object * uda_wildcarded_public_identity;
|
||||
struct dict_object * uda_wildcarded_impu;
|
||||
struct dict_object * uda_user_data;
|
||||
struct dict_object * uda_oc_supported_features;
|
||||
struct dict_object * uda_oc_feature_vector;
|
||||
|
||||
struct dict_object * uda_oc_olr;
|
||||
struct dict_object * uda_oc_sequence_number;
|
||||
struct dict_object * uda_oc_report_type;
|
||||
struct dict_object * uda_oc_reduction_percentage;
|
||||
struct dict_object * uda_oc_validity_duration;
|
||||
|
||||
struct dict_object * uda_failed_avp;
|
||||
struct dict_object * uda_proxy_info;
|
||||
struct dict_object * uda_route_record;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
< Profile-Update-Request > ::= < Diameter Header: 307, REQ, PXY, 16777217 >
|
||||
< Session-Id >
|
||||
[ DRMP ]
|
||||
{ Vendor-Specific-Application-Id }
|
||||
{ Auth-Session-State }
|
||||
{ Origin-Host }
|
||||
{ Origin-Realm }
|
||||
[ Destination-Host ]
|
||||
{ Destination-Realm }
|
||||
*[ Supported-Features ]
|
||||
{ User-Identity }
|
||||
[ Wildcarded-Public-Identity ]
|
||||
[ Wildcarded-IMPU ]
|
||||
[ User-Name ]
|
||||
*{ Data-Reference }
|
||||
{ User-Data }
|
||||
[ OC-Supported-Features ]
|
||||
*[ AVP ]
|
||||
*[ Proxy-Info ]
|
||||
*[ Route-Record ]
|
||||
*/
|
||||
struct sh_pur_msg{
|
||||
struct dict_object * pur_session_id ;
|
||||
struct dict_object * pur_drmp;
|
||||
|
||||
struct dict_object * pur_vendor_specific_application_id;
|
||||
struct dict_object * pur_auth_application_d;
|
||||
struct dict_object * pur_acct_application_id;
|
||||
|
||||
struct dict_object * pur_auth_session_state;
|
||||
struct dict_object * pur_origin_host;
|
||||
struct dict_object * pur_origin_realm;
|
||||
struct dict_object * pur_destination_host;
|
||||
struct dict_object * pur_destination_realm;
|
||||
|
||||
struct dict_object * pur_supported_features;
|
||||
struct dict_object * pur_vendor_id;
|
||||
struct dict_object * pur_feature_list_id;
|
||||
struct dict_object * pur_feature_list;
|
||||
|
||||
struct dict_object * pur_user_identity;
|
||||
struct dict_object * pur_public_identity;
|
||||
struct dict_object * pur_msisdn;
|
||||
|
||||
struct dict_object * pur_wildcarded_public_identity;
|
||||
struct dict_object * pur_wildcarded_impu;
|
||||
struct dict_object * pur_user_name;
|
||||
struct dict_object * pur_data_reference;
|
||||
|
||||
struct dict_object * pur_user_date;
|
||||
|
||||
struct dict_object * pur_oc_supported_features;
|
||||
struct dict_object * pur_oc_feature_vector;
|
||||
|
||||
struct dict_object * pur_proxy_info;
|
||||
struct dict_object * udr_route_record;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
< Profile-Update-Answer > ::=< Diameter Header: 307, PXY, 16777217 >
|
||||
< Session-Id >
|
||||
[ DRMP ]
|
||||
{ Vendor-Specific-Application-Id }
|
||||
[ Result-Code ]
|
||||
[ Experimental-Result ]
|
||||
{ Auth-Session-State }
|
||||
{ Origin-Host }
|
||||
{ Origin-Realm }
|
||||
[ Wildcarded-Public-Identity ]
|
||||
[ Wildcarded-IMPU ]
|
||||
[ Repository-Data-ID ]
|
||||
[ Data-Reference ]
|
||||
*[ Supported-Features ]
|
||||
[ OC-Supported-Features ]
|
||||
[ OC-OLR ]
|
||||
*[ AVP ]
|
||||
*[ Failed-AVP ]
|
||||
*[ Proxy-Info ]
|
||||
*[ Route-Record ]
|
||||
*/
|
||||
struct sh_pua_msg{
|
||||
struct dict_object * pua_session_id ;
|
||||
struct dict_object * pua_drmp;
|
||||
|
||||
struct dict_object * pua_vendor_specific_application_id;
|
||||
struct dict_object * pua_vendor_id;
|
||||
struct dict_object * pua_auth_application_d;
|
||||
struct dict_object * pua_acct_application_id;
|
||||
|
||||
struct dict_object * pua_result_code;
|
||||
|
||||
struct dict_object * pua_experimental_result;
|
||||
struct dict_object * pua_experimental_result_code;
|
||||
|
||||
struct dict_object * pua_auth_session_state;
|
||||
|
||||
struct dict_object * pua_origin_host;
|
||||
struct dict_object * pua_origin_realm;
|
||||
|
||||
struct dict_object * pua_wildcarded_public_identity;
|
||||
struct dict_object * pua_wildcarded_impu;
|
||||
|
||||
struct dict_object * pua_repository_data_id;
|
||||
struct dict_object * pua_service_indication;
|
||||
struct dict_object * pua_sequence_number;
|
||||
|
||||
struct dict_object * pua_data_reference;
|
||||
|
||||
struct dict_object * pua_supported_features;
|
||||
struct dict_object * pua_feature_list_id;
|
||||
struct dict_object * pua_feature_list;
|
||||
|
||||
struct dict_object * pua_oc_supported_features;
|
||||
struct dict_object * pua_oc_feature_vector;
|
||||
|
||||
struct dict_object * pua_oc_olr;
|
||||
struct dict_object * pua_oc_sequence_number;
|
||||
struct dict_object * pua_oc_report_type;
|
||||
struct dict_object * pua_oc_reduction_percentage;
|
||||
struct dict_object * pua_oc_validity_duration;
|
||||
|
||||
struct dict_object * pua_proxy_info;
|
||||
struct dict_object * pua_route_record;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* The module configuration */
|
||||
struct ta_conf {
|
||||
uint32_t vendor_id; /* default 999999 */
|
||||
uint32_t appli_id; /* default 123456 */
|
||||
uint32_t cmd_id; /* default 234567 */
|
||||
uint32_t avp_id; /* default 345678 */
|
||||
uint32_t long_avp_id; /* default 0 */
|
||||
size_t long_avp_len; /* default 5000 */
|
||||
int mode; /* default MODE_SERV | MODE_CLI */
|
||||
char * dest_realm; /* default local realm */
|
||||
char * dest_host; /* default NULL */
|
||||
char * user_name; /* default NULL */
|
||||
int signal; /* default TEST_APP_DEFAULT_SIGNAL */
|
||||
int bench_concur; /* default 100 */
|
||||
int bench_duration; /* default 10 */
|
||||
struct ta_stats {
|
||||
unsigned long long nb_echoed; /* server */
|
||||
unsigned long long nb_sent; /* client */
|
||||
unsigned long long nb_recv; /* client */
|
||||
unsigned long long nb_errs; /* client */
|
||||
unsigned long shortest; /* fastest answer, in microseconds */
|
||||
unsigned long longest; /* slowest answer, in microseconds */
|
||||
unsigned long avg; /* average answer time, in microseconds */
|
||||
} stats;
|
||||
pthread_mutex_t stats_lock;
|
||||
};
|
||||
extern struct ta_conf * ta_conf;
|
||||
|
||||
/* Parse the configuration file */
|
||||
int ta_conf_handle(char * conffile);
|
||||
|
||||
/* Handle incoming messages (server) */
|
||||
int sh_serv_init(void);
|
||||
void sh_serv_fini(void);
|
||||
|
||||
/* Create outgoing message (client) */
|
||||
int sh_cli_init(void);
|
||||
void sh_cli_finit(void);
|
||||
|
||||
/* Benchmark flavour */
|
||||
int ta_bench_init(void);
|
||||
void ta_bench_fini(void);
|
||||
|
||||
/* Initialize dictionary definitions */
|
||||
int ta_dict_init(void);
|
||||
|
||||
|
||||
int fd_sh_avp_search_avp ( struct avp * groupedavp, struct dict_object * what, struct avp ** avp );
|
||||
|
||||
|
||||
#endif /* __SH_APP_H__ */
|
||||
344
plat/diameter/extensions/sh_app/sh_bench.c
Normal file
344
plat/diameter/extensions/sh_app/sh_bench.c
Normal file
@@ -0,0 +1,344 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2015, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/* Create and send a message, and receive it */
|
||||
|
||||
#include "sh_app.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef __APPLE__ /* they deprecated the semaphore there... */
|
||||
#include <semaphore.h>
|
||||
|
||||
#define my_sem_t sem_t
|
||||
#define my_sem_init sem_init
|
||||
#define my_sem_destroy sem_destroy
|
||||
#define my_sem_timedwait sem_timedwait
|
||||
#define my_sem_post sem_post
|
||||
|
||||
#else // on APPLE
|
||||
#include <sched.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
#define my_sem_t dispatch_semaphore_t
|
||||
|
||||
static int my_sem_init(my_sem_t * s, int pshared, unsigned int value ) {
|
||||
*s = dispatch_semaphore_create(value);
|
||||
if (*s == NULL)
|
||||
return ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int my_sem_destroy(my_sem_t *s) {
|
||||
dispatch_release(*s);
|
||||
*s = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int my_sem_timedwait(my_sem_t * s, struct timespec *ts) {
|
||||
struct timespec tsn;
|
||||
int64_t nsec;
|
||||
dispatch_time_t when;
|
||||
|
||||
CHECK_SYS( clock_gettime(CLOCK_REALTIME, &tsn) );
|
||||
|
||||
nsec = (ts->tv_sec * 1000000000) + ts->tv_nsec
|
||||
- (tsn.tv_sec * 1000000000) - tsn.tv_nsec;
|
||||
|
||||
when = dispatch_time ( DISPATCH_TIME_NOW, nsec );
|
||||
|
||||
return dispatch_semaphore_wait ( *s, when ) ? ETIMEDOUT : 0;
|
||||
}
|
||||
|
||||
static int my_sem_post(my_sem_t *s) {
|
||||
dispatch_semaphore_signal(*s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // APPLE
|
||||
|
||||
|
||||
|
||||
struct ta_mess_info {
|
||||
int32_t randval; /* a random value to store in Test-AVP */
|
||||
struct timespec ts; /* Time of sending the message */
|
||||
};
|
||||
|
||||
static my_sem_t ta_sem; /* To handle the concurrency */
|
||||
|
||||
/* Cb called when an answer is received */
|
||||
#if 0
|
||||
|
||||
static void sh_cb_udr_ans(void * data, struct msg ** msg)
|
||||
{
|
||||
|
||||
struct ta_mess_info * mi = (struct ta_mess_info *)data;
|
||||
struct timespec ts;
|
||||
struct avp * avp;
|
||||
struct avp_hdr * hdr;
|
||||
unsigned long dur;
|
||||
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), return );
|
||||
|
||||
/* Value of Result Code */
|
||||
CHECK_FCT_DO( fd_msg_search_avp ( *msg, ta_res_code, &avp), return );
|
||||
if (avp) {
|
||||
CHECK_FCT_DO( fd_msg_avp_hdr( avp, &hdr ), return );
|
||||
}
|
||||
if (!avp || !hdr || hdr->avp_value->i32 != 2001) {
|
||||
/* error */
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), );
|
||||
ta_conf->stats.nb_errs++;
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), );
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Check value of Test-AVP */
|
||||
CHECK_FCT_DO( fd_msg_search_avp ( *msg, ta_avp, &avp), return );
|
||||
if (avp) {
|
||||
CHECK_FCT_DO( fd_msg_avp_hdr( avp, &hdr ), return );
|
||||
ASSERT(hdr->avp_value->i32 == mi->randval);
|
||||
}
|
||||
|
||||
/* Compute how long it took */
|
||||
dur = ((ts.tv_sec - mi->ts.tv_sec) * 1000000) + ((ts.tv_nsec - mi->ts.tv_nsec) / 1000);
|
||||
|
||||
/* Add this value to the stats */
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), );
|
||||
|
||||
if (ta_conf->stats.nb_recv) {
|
||||
/* Ponderate in the avg */
|
||||
ta_conf->stats.avg = (ta_conf->stats.avg * ta_conf->stats.nb_recv + dur) / (ta_conf->stats.nb_recv + 1);
|
||||
/* Min, max */
|
||||
if (dur < ta_conf->stats.shortest)
|
||||
ta_conf->stats.shortest = dur;
|
||||
if (dur > ta_conf->stats.longest)
|
||||
ta_conf->stats.longest = dur;
|
||||
} else {
|
||||
ta_conf->stats.shortest = dur;
|
||||
ta_conf->stats.longest = dur;
|
||||
ta_conf->stats.avg = dur;
|
||||
}
|
||||
ta_conf->stats.nb_recv++;
|
||||
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), );
|
||||
|
||||
end:
|
||||
/* Free the message */
|
||||
CHECK_FCT_DO(fd_msg_free(*msg), );
|
||||
*msg = NULL;
|
||||
|
||||
free(mi);
|
||||
|
||||
/* Post the semaphore */
|
||||
CHECK_SYS_DO( my_sem_post(&ta_sem), );
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Create a test message */
|
||||
static void ta_bench_test_message()
|
||||
{
|
||||
#if 0
|
||||
struct msg * req = NULL;
|
||||
struct avp * avp;
|
||||
union avp_value val;
|
||||
struct ta_mess_info * mi = NULL;
|
||||
|
||||
TRACE_DEBUG(FULL, "Creating a new message for sending.");
|
||||
|
||||
/* Create the request */
|
||||
CHECK_FCT_DO( fd_msg_new( ta_cmd_r, MSGFL_ALLOC_ETEID, &req ), goto out );
|
||||
|
||||
/* Create a new session */
|
||||
#define TEST_APP_SID_OPT "app_testb"
|
||||
CHECK_FCT_DO( fd_msg_new_session( req, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out );
|
||||
|
||||
/* Create the random value to store with the session */
|
||||
mi = malloc(sizeof(struct ta_mess_info));
|
||||
if (mi == NULL) {
|
||||
fd_log_debug("malloc failed: %s", strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
mi->randval = (int32_t)random();
|
||||
|
||||
/* Now set all AVPs values */
|
||||
|
||||
/* Set the Destination-Realm AVP */
|
||||
{
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( ta_dest_realm, 0, &avp ), goto out );
|
||||
val.os.data = (unsigned char *)(ta_conf->dest_realm);
|
||||
val.os.len = strlen(ta_conf->dest_realm);
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out );
|
||||
CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ), goto out );
|
||||
}
|
||||
|
||||
/* Set the Destination-Host AVP if needed*/
|
||||
if (ta_conf->dest_host) {
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( ta_dest_host, 0, &avp ), goto out );
|
||||
val.os.data = (unsigned char *)(ta_conf->dest_host);
|
||||
val.os.len = strlen(ta_conf->dest_host);
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out );
|
||||
CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ), goto out );
|
||||
}
|
||||
|
||||
/* Set Origin-Host & Origin-Realm */
|
||||
CHECK_FCT_DO( fd_msg_add_origin ( req, 0 ), goto out );
|
||||
|
||||
/* Set the User-Name AVP if needed*/
|
||||
if (ta_conf->user_name) {
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( ta_user_name, 0, &avp ), goto out );
|
||||
val.os.data = (unsigned char *)(ta_conf->user_name);
|
||||
val.os.len = strlen(ta_conf->user_name);
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out );
|
||||
CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ), goto out );
|
||||
}
|
||||
|
||||
/* Set the Test-AVP AVP */
|
||||
{
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( ta_avp, 0, &avp ), goto out );
|
||||
val.i32 = mi->randval;
|
||||
CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out );
|
||||
CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ), goto out );
|
||||
}
|
||||
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &mi->ts), goto out );
|
||||
|
||||
/* Send the request */
|
||||
CHECK_FCT_DO( fd_msg_send( &req, sh_rec_uda, mi ), goto out );
|
||||
|
||||
/* Increment the counter */
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), );
|
||||
ta_conf->stats.nb_sent++;
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), );
|
||||
|
||||
out:
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* The function called when the signal is received */
|
||||
static void ta_bench_start() {
|
||||
struct timespec end_time, now;
|
||||
struct ta_stats start, end;
|
||||
int nsec = 0;
|
||||
|
||||
/* Save the initial stats */
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), );
|
||||
memcpy(&start, &ta_conf->stats, sizeof(struct ta_stats));
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), );
|
||||
|
||||
/* We will run for ta_conf->bench_duration seconds */
|
||||
LOG_N("Starting benchmark client, %ds", ta_conf->bench_duration);
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &end_time), );
|
||||
end_time.tv_sec += ta_conf->bench_duration;
|
||||
|
||||
/* Now loop until timeout is reached */
|
||||
do {
|
||||
/* Do not create more that NB_CONCURRENT_MESSAGES in paralel */
|
||||
int ret = my_sem_timedwait(&ta_sem, &end_time);
|
||||
if (ret == -1) {
|
||||
ret = errno;
|
||||
if (ret != ETIMEDOUT) {
|
||||
CHECK_POSIX_DO(ret, ); /* Just to log it */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update the current time */
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), );
|
||||
|
||||
if (!TS_IS_INFERIOR(&now, &end_time))
|
||||
break;
|
||||
|
||||
/* Create and send a new test message */
|
||||
ta_bench_test_message();
|
||||
} while (1);
|
||||
|
||||
do {
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), );
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), ); /* Re-read the time because we might have spent some time wiating for the mutex */
|
||||
memcpy(&end, &ta_conf->stats, sizeof(struct ta_stats));
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), );
|
||||
|
||||
/* Now, display the statistics */
|
||||
LOG_N( "------- app_test Benchmark results, end sending +%ds ---------", nsec);
|
||||
if (now.tv_nsec >= end_time.tv_nsec) {
|
||||
LOG_N( " Executing for: %d.%06ld sec",
|
||||
(int)(now.tv_sec + ta_conf->bench_duration - end_time.tv_sec),
|
||||
(long)(now.tv_nsec - end_time.tv_nsec) / 1000);
|
||||
} else {
|
||||
LOG_N( " Executing for: %d.%06ld sec",
|
||||
(int)(now.tv_sec + ta_conf->bench_duration - 1 - end_time.tv_sec),
|
||||
(long)(now.tv_nsec + 1000000000 - end_time.tv_nsec) / 1000);
|
||||
}
|
||||
LOG_N( " %llu messages sent", end.nb_sent - start.nb_sent);
|
||||
LOG_N( " %llu error(s) received", end.nb_errs - start.nb_errs);
|
||||
LOG_N( " %llu answer(s) received", end.nb_recv - start.nb_recv);
|
||||
LOG_N( " Overall:");
|
||||
LOG_N( " fastest: %ld.%06ld sec.", end.shortest / 1000000, end.shortest % 1000000);
|
||||
LOG_N( " slowest: %ld.%06ld sec.", end.longest / 1000000, end.longest % 1000000);
|
||||
LOG_N( " Average: %ld.%06ld sec.", end.avg / 1000000, end.avg % 1000000);
|
||||
LOG_N( " Throughput: %llu messages / sec", (end.nb_recv - start.nb_recv) / (( now.tv_sec + ta_conf->bench_duration - end_time.tv_sec ) + ((now.tv_nsec - end_time.tv_nsec) / 1000000000)));
|
||||
LOG_N( "-------------------------------------");
|
||||
|
||||
nsec ++;
|
||||
sleep(1);
|
||||
} while ( (end.nb_sent - start.nb_sent) > (end.nb_errs - start.nb_errs) + (end.nb_recv - start.nb_recv) );
|
||||
LOG_N( "--------------- Test Complete --------------");
|
||||
|
||||
}
|
||||
|
||||
|
||||
int ta_bench_init(void)
|
||||
{
|
||||
CHECK_SYS( my_sem_init( &ta_sem, 0, ta_conf->bench_concur) );
|
||||
|
||||
CHECK_FCT( fd_event_trig_regcb(ta_conf->signal, "test_app.bench", ta_bench_start ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ta_bench_fini(void)
|
||||
{
|
||||
// CHECK_FCT_DO( fd_sig_unregister(ta_conf->signal), /* continue */ );
|
||||
|
||||
CHECK_SYS_DO( my_sem_destroy(&ta_sem), );
|
||||
|
||||
return;
|
||||
};
|
||||
997
plat/diameter/extensions/sh_app/sh_cli.c
Normal file
997
plat/diameter/extensions/sh_app/sh_cli.c
Normal file
@@ -0,0 +1,997 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/* Create and send a message, and receive it */
|
||||
|
||||
/* Note that we use both sessions and the argument to answer callback to pass the same value.
|
||||
* This is just for the purpose of checking everything went OK.
|
||||
*/
|
||||
#include "sh_app.h"
|
||||
#include <stdio.h>
|
||||
#include "sh_conf.h"
|
||||
|
||||
// static struct disp_hdl * sh_hdl_fb = NULL; /* handler for fallback cb */
|
||||
extern struct dict_object * sh_appli;
|
||||
static struct disp_hdl * sh_hdl_uda = NULL; /* handler for PUR req cb */
|
||||
static struct disp_hdl * sh_hdl_pua = NULL; /* handler for PUR req cb */
|
||||
extern struct dict_object * uda_cmd;
|
||||
extern struct dict_object * pua_cmd;
|
||||
|
||||
|
||||
struct sess_state {
|
||||
int32_t randval; /* a random value to store in Test-AVP */
|
||||
struct timespec ts; /* Time of sending the message */
|
||||
} ;
|
||||
|
||||
|
||||
static struct session_handler * sh_cli_reg = NULL;
|
||||
|
||||
static struct sh_udr_msg g_udr_cmd;
|
||||
static struct sh_pur_msg g_pur_cmd;
|
||||
|
||||
static struct sh_uda_msg g_uda_cmd;
|
||||
static struct sh_pua_msg g_pua_cmd;
|
||||
|
||||
|
||||
//static struct dict_avp_request __avp;
|
||||
|
||||
static char * g_test_buf = NULL;
|
||||
static size_t g_test_len;
|
||||
#define FD_DUMP_TEST_PARAMS &g_test_buf, &g_test_len, NULL
|
||||
#define SH_TEST_ON 1
|
||||
|
||||
|
||||
#if 0
|
||||
static void sh_send_pur()
|
||||
{
|
||||
struct msg *pur_msg = NULL;
|
||||
struct avp *avp, *grpavp;
|
||||
union avp_value val;
|
||||
struct sess_state *mi = NULL, *svg;
|
||||
struct session *sess = NULL;
|
||||
|
||||
TRACE_DEBUG(FULL, "Creating a new message for sending.");
|
||||
|
||||
/* Create a new session */
|
||||
#define TEST_APP_SID_OPT "sh_app"
|
||||
|
||||
/* Create the message object from model */
|
||||
{
|
||||
struct dict_object * acr_model = NULL;
|
||||
|
||||
/* Now find the UDR dictionary object */
|
||||
ASSERT( 0 == fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Profile-Update-Request", &acr_model, ENOENT ) );
|
||||
|
||||
/* Create the instance, using the templates */
|
||||
ASSERT( 0 == fd_msg_new ( acr_model, MSGFL_ALLOC_ETEID, &pur_msg ) );
|
||||
|
||||
/* set application id */
|
||||
{
|
||||
struct msg_hdr * msg_hdr = NULL;
|
||||
ASSERT( 0 == fd_msg_hdr ( pur_msg, &msg_hdr ) );
|
||||
msg_hdr->msg_appl = SH_APP_ID;
|
||||
}
|
||||
|
||||
/* Check there is no child */
|
||||
ASSERT( ENOENT == fd_msg_browse ( pur_msg, MSG_BRW_FIRST_CHILD, NULL, NULL) );
|
||||
}
|
||||
|
||||
|
||||
CHECK_FCT_DO( fd_msg_new_session( pur_msg, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out );
|
||||
CHECK_FCT_DO( fd_msg_sess_get(fd_g_config->cnf_dict, pur_msg, &sess, NULL), goto out );
|
||||
|
||||
/* Create the random value to store with the session */
|
||||
mi = malloc(sizeof(struct sess_state));
|
||||
if (mi == NULL) {
|
||||
fd_log_debug("malloc failed: %s", strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
mi->randval = (int32_t)random();
|
||||
|
||||
/* Now resolve some other useful AVPs */
|
||||
/* resolve udr avps */
|
||||
SEARCH_AVP_("Session-Id", 0, &g_pur_cmd.pur_session_id);
|
||||
SEARCH_AVP_("DRMP", SH_VND_ID, &g_pur_cmd.pur_drmp);
|
||||
SEARCH_AVP_("Vendor-Specific-Application-Id", 0, &g_pur_cmd.pur_vendor_specific_application_id);
|
||||
SEARCH_AVP_("Auth-Session-State", 0, &g_pur_cmd.pur_auth_session_state);
|
||||
SEARCH_AVP_("Origin-Host", 0, &g_pur_cmd.pur_origin_host);
|
||||
SEARCH_AVP_("Origin-Realm", 0, &g_pur_cmd.pur_origin_realm);
|
||||
SEARCH_AVP_("Destination-Host", 0, &g_pur_cmd.pur_destination_host);
|
||||
SEARCH_AVP_("Destination-Realm", 0, &g_pur_cmd.pur_destination_realm);
|
||||
|
||||
SEARCH_AVP_("Supported-Features", SH_VND_ID, &g_pur_cmd.pur_supported_features);
|
||||
SEARCH_AVP_("User-Identity", SH_VND_ID, &g_pur_cmd.pur_user_identity);
|
||||
SEARCH_AVP_("Wildcarded-Public-Identity", SH_VND_ID, &g_pur_cmd.pur_wildcarded_public_identity);
|
||||
SEARCH_AVP_("Wildcarded-IMPU", SH_VND_ID, &g_pur_cmd.pur_wildcarded_impu);
|
||||
SEARCH_AVP_("User-Name", 0, &g_pur_cmd.pur_user_name);
|
||||
SEARCH_AVP_("Data-Reference", SH_VND_ID, &g_pur_cmd.pur_data_reference);
|
||||
|
||||
SEARCH_AVP_("User-Data", SH_VND_ID, &g_pur_cmd.pur_user_date);
|
||||
SEARCH_AVP_("OC-Supported-Features", SH_VND_ID, &g_pur_cmd.pur_oc_supported_features);
|
||||
|
||||
/* Now set all AVPs values */
|
||||
EN_AVP_U32(g_pur_cmd.pur_drmp, 0, pur_msg, "DRMP Ok")
|
||||
|
||||
/* Set Vendor-Specific-Application-Id AVP if needed*/
|
||||
{
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( g_pur_cmd.pur_vendor_specific_application_id, 0, &grpavp ), goto out );
|
||||
|
||||
EN_GRPAVP_U32("Vendor-Id", 0, g_pur_cmd.pur_vendor_id, SH_VND_ID)
|
||||
EN_GRPAVP_U32("Auth-Application-Id", 0, g_pur_cmd.pur_auth_application_d, SH_APP_ID)
|
||||
EN_GRPAVP_U32("Acct-Application-Id", 0,g_pur_cmd.pur_acct_application_id, SH_APP_ID)
|
||||
|
||||
CHECK_FCT_DO( fd_msg_avp_add( pur_msg, MSG_BRW_LAST_CHILD, grpavp ), goto out );
|
||||
|
||||
LOG_D("Vendor-Specific-Application-Id Ok\n");
|
||||
}
|
||||
|
||||
EN_AVP_U32(g_pur_cmd.pur_auth_session_state, 1, pur_msg, "pur_auth_session_state Ok\n")
|
||||
|
||||
/* Set Origin-Host & Origin-Realm AVP */
|
||||
CHECK_FCT_DO( fd_msg_add_origin ( pur_msg, 0 ), goto out );
|
||||
|
||||
/* Set the Destination-Host AVP if needed*/
|
||||
if (ta_conf->dest_host) {
|
||||
EN_AVP_STR(g_pur_cmd.pur_destination_host, g_sh_conf_ext.pi_diamid_peer, pur_msg, "pur_origin_host Ok");
|
||||
}
|
||||
|
||||
/* Set the Destination-Realm AVP */
|
||||
EN_AVP_STR(g_pur_cmd.pur_destination_realm, g_sh_conf_ext.pi_diamid_realm_peer, pur_msg, "pur_origin_realm Ok");
|
||||
|
||||
/* Set the Supported-Features group AVP if needed*/
|
||||
{
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( g_pur_cmd.pur_supported_features, 0, &grpavp ), goto out );
|
||||
|
||||
EN_GRPAVP_U32("Vendor-Id", 0, g_pur_cmd.pur_vendor_id, SH_VND_ID)
|
||||
EN_GRPAVP_U32("Feature-List-ID", SH_VND_ID,g_pur_cmd.pur_feature_list_id, 2)
|
||||
EN_GRPAVP_U32("Feature-List", SH_VND_ID,g_pur_cmd.pur_feature_list, 3)
|
||||
|
||||
CHECK_FCT_DO( fd_msg_avp_add( pur_msg, MSG_BRW_LAST_CHILD, grpavp ), goto out );
|
||||
|
||||
LOG_D("Supported-Features Ok\n");
|
||||
}
|
||||
|
||||
/* Set the User-Identity AVP if needed*/
|
||||
{
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( g_pur_cmd.pur_user_identity, 0, &grpavp ), goto out );
|
||||
|
||||
EN_GRPAVP_STR("Public-Identity", SH_VND_ID, g_pur_cmd.pur_public_identity, "public_id", grpavp)
|
||||
EN_GRPAVP_STR("MSISDN", SH_VND_ID, g_pur_cmd.pur_msisdn, "12345", grpavp)
|
||||
|
||||
CHECK_FCT_DO( fd_msg_avp_add( pur_msg, MSG_BRW_LAST_CHILD, grpavp ), goto out );
|
||||
|
||||
LOG_D("pur_user_identity Ok\n");
|
||||
}
|
||||
|
||||
EN_AVP_STR( g_pur_cmd.pur_wildcarded_public_identity, "wildcarded_public_id", pur_msg, "wildcarded_public_id Ok")
|
||||
EN_AVP_STR( g_pur_cmd.pur_wildcarded_impu, "wildcarded_impu", pur_msg, "wildcarded_impu Ok")
|
||||
EN_AVP_STR( g_pur_cmd.pur_user_name, "User-Name", pur_msg, "user_name Ok")
|
||||
EN_AVP_U32( g_pur_cmd.pur_data_reference, 1,pur_msg, "Data-Reference Ok")
|
||||
EN_AVP_STR( g_pur_cmd.pur_user_date, "User-Data", pur_msg, "User-Data Ok")
|
||||
|
||||
/* Set the OC-Supported-Features AVP */
|
||||
{
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( g_pur_cmd.pur_oc_supported_features, 0, &grpavp ), goto out);
|
||||
|
||||
EN_GRPAVP_U64("OC-Feature-Vector", SH_VND_ID, g_pur_cmd.pur_oc_feature_vector, 1)
|
||||
|
||||
CHECK_FCT_DO( fd_msg_avp_add( pur_msg, MSG_BRW_LAST_CHILD, grpavp ), goto out );
|
||||
|
||||
LOG_D("OC-Feature-Vector Ok\n");
|
||||
#if SH_TEST_ON
|
||||
fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, pur_msg, fd_g_config->cnf_dict, 0, 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &mi->ts), goto out );
|
||||
LOG_D("CLOCK_REALTIME Ok\n");
|
||||
|
||||
/* Keep a pointer to the session data for debug purpose, in real life we would not need it */
|
||||
svg = mi;
|
||||
|
||||
/* Store this value in the session */
|
||||
// CHECK_FCT_DO( fd_sess_state_store ( sh_cli_reg, sess, &mi ), goto out );
|
||||
LOG_D("sess Ok\n");
|
||||
|
||||
/* Log sending the message */
|
||||
fprintf(stderr, "SEND %x to '%s' (%s)\n", svg->randval, ta_conf->dest_realm, ta_conf->dest_host?:"-" );
|
||||
fflush(stderr);
|
||||
|
||||
// assert( 0 == fd_msg_source_set( pur_msg, "client.domain", CONSTSTRLEN("client.domain") ) );
|
||||
|
||||
/* Send the request */
|
||||
CHECK_FCT_DO( fd_msg_send( &pur_msg, NULL, svg ), goto out );
|
||||
LOG_D("fd_msg_send Ok\n");
|
||||
|
||||
/* Increment the counter */
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), );
|
||||
ta_conf->stats.nb_sent++;
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), );
|
||||
|
||||
out:
|
||||
printf("end\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void sh_send_udr()
|
||||
{
|
||||
struct msg *udr_msg = NULL;
|
||||
struct avp *avp, *grpavp;
|
||||
union avp_value val;
|
||||
struct sess_state *mi = NULL, *svg;
|
||||
struct session *sess = NULL;
|
||||
|
||||
TRACE_DEBUG(FULL, "Creating a new message for sending.");
|
||||
|
||||
/* Create a new session */
|
||||
#define TEST_APP_SID_OPT "sh_app"
|
||||
|
||||
/* Create the message object from model */
|
||||
{
|
||||
struct dict_object * acr_model = NULL;
|
||||
|
||||
/* Now find the UDR dictionary object */
|
||||
ASSERT( 0 == fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "User-Data-Request", &acr_model, ENOENT ) );
|
||||
|
||||
/* Create the instance, using the templates */
|
||||
ASSERT( 0 == fd_msg_new ( acr_model, MSGFL_ALLOC_ETEID, &udr_msg ) );
|
||||
|
||||
/* set application id */
|
||||
{
|
||||
struct msg_hdr * msg_hdr = NULL;
|
||||
ASSERT( 0 == fd_msg_hdr ( udr_msg, &msg_hdr ) );
|
||||
msg_hdr->msg_appl = SH_APP_ID;
|
||||
msg_hdr->msg_flags = msg_hdr->msg_flags & (~CMD_FLAG_PROXIABLE);
|
||||
}
|
||||
|
||||
/* Check there is no child */
|
||||
ASSERT( ENOENT == fd_msg_browse ( udr_msg, MSG_BRW_FIRST_CHILD, NULL, NULL) );
|
||||
}
|
||||
|
||||
|
||||
CHECK_FCT_DO( fd_msg_new_session( udr_msg, (os0_t)TEST_APP_SID_OPT, CONSTSTRLEN(TEST_APP_SID_OPT) ), goto out );
|
||||
CHECK_FCT_DO( fd_msg_sess_get(fd_g_config->cnf_dict, udr_msg, &sess, NULL), goto out );
|
||||
|
||||
/* Create the random value to store with the session */
|
||||
mi = malloc(sizeof(struct sess_state));
|
||||
if (mi == NULL) {
|
||||
fd_log_debug("malloc failed: %s", strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
mi->randval = (int32_t)random();
|
||||
|
||||
/* Now resolve some other useful AVPs */
|
||||
/* resolve udr avps */
|
||||
SEARCH_AVP_("Session-Id", 0, &g_udr_cmd.udr_session_id);
|
||||
SEARCH_AVP_("DRMP", SH_VND_ID, &g_udr_cmd.udr_drmp);
|
||||
SEARCH_AVP_("Vendor-Specific-Application-Id", 0, &g_udr_cmd.udr_vendor_specific_application_id);
|
||||
SEARCH_AVP_("Auth-Session-State", 0, &g_udr_cmd.udr_auth_session_state);
|
||||
SEARCH_AVP_("Origin-Host", 0, &g_udr_cmd.udr_origin_host);
|
||||
SEARCH_AVP_("Origin-Realm", 0, &g_udr_cmd.udr_origin_realm);
|
||||
SEARCH_AVP_("Destination-Host", 0, &g_udr_cmd.udr_destination_host);
|
||||
SEARCH_AVP_("Destination-Realm", 0, &g_udr_cmd.udr_destination_realm);
|
||||
|
||||
SEARCH_AVP_("Supported-Features", SH_VND_ID, &g_udr_cmd.udr_supported_features);
|
||||
SEARCH_AVP_("User-Identity", SH_VND_ID, &g_udr_cmd.udr_user_identity);
|
||||
SEARCH_AVP_("Wildcarded-Public-Identity", SH_VND_ID, &g_udr_cmd.udr_wildcarded_public_identity);
|
||||
SEARCH_AVP_("Wildcarded-IMPU", SH_VND_ID, &g_udr_cmd.udr_wildcarded_impu);
|
||||
SEARCH_AVP_("Server-Name", SH_VND_ID, &g_udr_cmd.udr_server_name);
|
||||
SEARCH_AVP_("Service-Indication", SH_VND_ID, &g_udr_cmd.udr_service_indication);
|
||||
SEARCH_AVP_("Data-Reference", SH_VND_ID, &g_udr_cmd.udr_data_reference);
|
||||
SEARCH_AVP_("Identity-Set", SH_VND_ID, &g_udr_cmd.udr_identity_set);
|
||||
SEARCH_AVP_("Requested-Domain", SH_VND_ID, &g_udr_cmd.udr_requested_domain);
|
||||
SEARCH_AVP_("Current-Location", SH_VND_ID, &g_udr_cmd.udr_current_location);
|
||||
SEARCH_AVP_("DSAI-Tag", SH_VND_ID, &g_udr_cmd.udr_dsai_tag);
|
||||
SEARCH_AVP_("Session-Priority", SH_VND_ID, &g_udr_cmd.udr_session_priority);
|
||||
SEARCH_AVP_("User-Name", 0, &g_udr_cmd.udr_user_name);
|
||||
SEARCH_AVP_("Requested-Nodes", SH_VND_ID, &g_udr_cmd.udr_requested_nodes);
|
||||
SEARCH_AVP_("Serving-Node-Indication", SH_VND_ID, &g_udr_cmd.udr_serving_node_indication);
|
||||
SEARCH_AVP_("Pre-paging-Supported", SH_VND_ID, &g_udr_cmd.udr_pre_paging_supported);
|
||||
SEARCH_AVP_("Local-Time-Zone-Indication", SH_VND_ID, &g_udr_cmd.udr_local_time_zone_indication);
|
||||
SEARCH_AVP_("UDR-Flags", SH_VND_ID, &g_udr_cmd.udr_udr_flags);
|
||||
SEARCH_AVP_("Call-Reference-Info", SH_VND_ID, &g_udr_cmd.udr_call_reference_info);
|
||||
SEARCH_AVP_("OC-Supported-Features", SH_VND_ID, &g_udr_cmd.udr_oc_supported_features);
|
||||
|
||||
/* Now set all AVPs values */
|
||||
EN_AVP_U32(g_udr_cmd.udr_drmp, 0, udr_msg, "DRMP Ok")
|
||||
|
||||
/* Set Vendor-Specific-Application-Id AVP if needed*/
|
||||
{
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( g_udr_cmd.udr_vendor_specific_application_id, 0, &grpavp ), goto out );
|
||||
|
||||
EN_GRPAVP_U32("Vendor-Id", 0, g_udr_cmd.udr_vendor_id, SH_VND_ID)
|
||||
EN_GRPAVP_U32("Auth-Application-Id", 0, g_udr_cmd.udr_auth_application_d, SH_APP_ID)
|
||||
EN_GRPAVP_U32("Acct-Application-Id", 0,g_udr_cmd.udr_acct_application_id, SH_APP_ID)
|
||||
|
||||
CHECK_FCT_DO( fd_msg_avp_add( udr_msg, MSG_BRW_LAST_CHILD, grpavp ), goto out );
|
||||
|
||||
LOG_D("Vendor-Specific-Application-Id Ok\n");
|
||||
}
|
||||
|
||||
EN_AVP_U32(g_udr_cmd.udr_auth_session_state, 1, udr_msg, "udr_auth_session_state Ok\n")
|
||||
|
||||
/* Set Origin-Host & Origin-Realm AVP */
|
||||
CHECK_FCT_DO( fd_msg_add_origin ( udr_msg, 0 ), goto out );
|
||||
|
||||
/* Set the Destination-Host AVP if needed*/
|
||||
if (ta_conf->dest_host) {
|
||||
EN_AVP_STR(g_udr_cmd.udr_destination_host, g_sh_conf_ext.pi_diamid_peer, udr_msg, "udr_origin_host Ok");
|
||||
}
|
||||
|
||||
/* Set the Destination-Realm AVP */
|
||||
EN_AVP_STR(g_udr_cmd.udr_destination_realm, g_sh_conf_ext.pi_diamid_realm_peer, udr_msg, "udr_origin_realm Ok");
|
||||
|
||||
/* Set the Supported-Features group AVP if needed*/
|
||||
{
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( g_udr_cmd.udr_supported_features, 0, &grpavp ), goto out );
|
||||
|
||||
EN_GRPAVP_U32("Vendor-Id", 0, g_udr_cmd.udr_vendor_id, 1)
|
||||
EN_GRPAVP_U32("Feature-List-ID", SH_VND_ID,g_udr_cmd.udr_feature_list_id, 2)
|
||||
EN_GRPAVP_U32("Feature-List", SH_VND_ID,g_udr_cmd.udr_feature_list, 3)
|
||||
|
||||
CHECK_FCT_DO( fd_msg_avp_add( udr_msg, MSG_BRW_LAST_CHILD, grpavp ), goto out );
|
||||
|
||||
LOG_D("Supported-Features Ok\n");
|
||||
}
|
||||
|
||||
/* Set the User-Identity AVP if needed*/
|
||||
{
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( g_udr_cmd.udr_user_identity, 0, &grpavp ), goto out );
|
||||
|
||||
EN_GRPAVP_STR("Public-Identity", SH_VND_ID, g_udr_cmd.udr_public_identity, "public_id", grpavp)
|
||||
EN_GRPAVP_STR("MSISDN", SH_VND_ID, g_udr_cmd.udr_msisdn, "12345", grpavp)
|
||||
|
||||
CHECK_FCT_DO( fd_msg_avp_add( udr_msg, MSG_BRW_LAST_CHILD, grpavp ), goto out );
|
||||
|
||||
LOG_D("udr_user_identity Ok\n");
|
||||
}
|
||||
|
||||
EN_AVP_STR(g_udr_cmd.udr_wildcarded_public_identity, "Wildcarded-public-ID", udr_msg, "Wildcarded-Public-ID Ok")
|
||||
EN_AVP_STR( g_udr_cmd.udr_wildcarded_impu, "Wildcarded-IMPU", udr_msg, "Wildcarded-IMPU Ok")
|
||||
EN_AVP_STR( g_udr_cmd.udr_server_name, "Server-Name", udr_msg, "Server-Name Ok")
|
||||
EN_AVP_STR( g_udr_cmd.udr_service_indication, "Service-Indication", udr_msg, "Service-Indication Ok")
|
||||
EN_AVP_U32(g_udr_cmd.udr_data_reference, 1,udr_msg, "Data-Reference Ok")
|
||||
EN_AVP_U32(g_udr_cmd.udr_identity_set, 1,udr_msg, "Identity-Set Ok")
|
||||
|
||||
EN_AVP_U32(g_udr_cmd.udr_requested_domain, 2,udr_msg, "Req-Domain Ok")
|
||||
|
||||
EN_AVP_U32( g_udr_cmd.udr_current_location, 3, udr_msg, "Cur-Location Ok")
|
||||
EN_AVP_STR( g_udr_cmd.udr_dsai_tag, "DSAI-Tag", udr_msg, "DSAI-Tag Ok")
|
||||
|
||||
EN_AVP_U32( g_udr_cmd.udr_session_priority, 4, udr_msg, "Session-Priority Ok")
|
||||
EN_AVP_STR( g_udr_cmd.udr_user_name, "User-Name", udr_msg, "User-Name Ok")
|
||||
|
||||
/* Set User-Name AVP */
|
||||
EN_AVP_U32( g_udr_cmd.udr_requested_nodes, 5, udr_msg, "Requested-Nodes Ok")
|
||||
EN_AVP_U32( g_udr_cmd.udr_serving_node_indication, 6, udr_msg, "Serving-Node-Indication Ok")
|
||||
EN_AVP_U32( g_udr_cmd.udr_pre_paging_supported, 7, udr_msg, "Pre-paging-Supported Ok")
|
||||
EN_AVP_U32( g_udr_cmd.udr_local_time_zone_indication, 8, udr_msg, "Local-Time-Zone-Indication Ok")
|
||||
|
||||
EN_AVP_U32( g_udr_cmd.udr_udr_flags, 9, udr_msg, "UDR-Flags Ok")
|
||||
|
||||
/* Set the Call-Reference-Info AVP */
|
||||
{
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( g_udr_cmd.udr_call_reference_info, 0, &grpavp ), goto out );
|
||||
|
||||
EN_GRPAVP_STR("Call-Reference-Number", SH_VND_ID, g_udr_cmd.udr_call_reference_number, "Call-Reference-Number", grpavp)
|
||||
EN_GRPAVP_STR("AS-Number", SH_VND_ID, g_udr_cmd.udr_as_number, "AS-Number", grpavp)
|
||||
|
||||
CHECK_FCT_DO( fd_msg_avp_add( udr_msg, MSG_BRW_LAST_CHILD, grpavp ), goto out );
|
||||
|
||||
LOG_D("Call-Reference-Info Ok\n");
|
||||
}
|
||||
|
||||
/* Set the OC-Supported-Features AVP */
|
||||
{
|
||||
CHECK_FCT_DO( fd_msg_avp_new ( g_udr_cmd.udr_oc_supported_features, 0, &grpavp ), goto out);
|
||||
|
||||
EN_GRPAVP_U64("OC-Feature-Vector", SH_VND_ID, g_udr_cmd.udr_oc_feature_vector, 1)
|
||||
|
||||
CHECK_FCT_DO( fd_msg_avp_add( udr_msg, MSG_BRW_LAST_CHILD, grpavp ), goto out );
|
||||
|
||||
LOG_D("OC-Feature-Vector Ok\n");
|
||||
#if SH_TEST_ON
|
||||
fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, udr_msg, fd_g_config->cnf_dict, 0, 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &mi->ts), goto out );
|
||||
LOG_D("CLOCK_REALTIME Ok\n");
|
||||
|
||||
/* Keep a pointer to the session data for debug purpose, in real life we would not need it */
|
||||
svg = mi;
|
||||
|
||||
/* Store this value in the session */
|
||||
CHECK_FCT_DO( fd_sess_state_store ( sh_cli_reg, sess, &mi ), goto out );
|
||||
LOG_D("sess Ok\n");
|
||||
|
||||
/* Log sending the message */
|
||||
fprintf(stderr, "SEND %x to '%s' (%s)\n", svg->randval, ta_conf->dest_realm, ta_conf->dest_host?:"-" );
|
||||
fflush(stderr);
|
||||
|
||||
/* Send the request */
|
||||
CHECK_FCT_DO( fd_msg_send( &udr_msg, NULL, svg ), goto out );
|
||||
LOG_D("fd_msg_send Ok\n");
|
||||
|
||||
/* Increment the counter */
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), );
|
||||
ta_conf->stats.nb_sent++;
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), );
|
||||
|
||||
out:
|
||||
printf("end\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
static int sh_parse_pua( struct msg ** msg)
|
||||
{
|
||||
struct msg* pua_msg = *msg;
|
||||
struct avp *avp, *grpavp=NULL;
|
||||
struct avp_hdr *avphdr;
|
||||
|
||||
LOG_D("fj sh_parse_pua");
|
||||
|
||||
SEARCH_AVP_("Session-Id", 0, &g_pua_cmd.pua_session_id);
|
||||
SEARCH_AVP_("DRMP", SH_VND_ID, &g_pua_cmd.pua_drmp);
|
||||
|
||||
SEARCH_AVP_("Vendor-Specific-Application-Id", 0, &g_pua_cmd.pua_vendor_specific_application_id);
|
||||
SEARCH_AVP_("Vendor-Id", 0, &g_pua_cmd.pua_vendor_id);
|
||||
SEARCH_AVP_("Auth-Application-Id", 0, &g_pua_cmd.pua_auth_application_d);
|
||||
SEARCH_AVP_("Acct-Application-Id", 0, &g_pua_cmd.pua_acct_application_id);
|
||||
|
||||
|
||||
SEARCH_AVP_("Result-Code", 0, &g_pua_cmd.pua_result_code);
|
||||
|
||||
SEARCH_AVP_("Experimental-Result", 0, &g_pua_cmd.pua_experimental_result);
|
||||
SEARCH_AVP_("Experimental-Result-Code", 0, &g_pua_cmd.pua_experimental_result_code);
|
||||
|
||||
SEARCH_AVP_("Auth-Session-State", 0, &g_pua_cmd.pua_auth_session_state);
|
||||
SEARCH_AVP_("Origin-Host", 0, &g_pua_cmd.pua_origin_host);
|
||||
SEARCH_AVP_("Origin-Realm", 0, &g_pua_cmd.pua_origin_realm);
|
||||
|
||||
|
||||
SEARCH_AVP_("Wildcarded-Public-Identity", SH_VND_ID, &g_pua_cmd.pua_wildcarded_public_identity );
|
||||
SEARCH_AVP_("Wildcarded-IMPU", SH_VND_ID, &g_pua_cmd.pua_wildcarded_impu );
|
||||
|
||||
SEARCH_AVP_("Repository-Data-ID", SH_VND_ID, &g_pua_cmd.pua_repository_data_id );
|
||||
SEARCH_AVP_("Service-Indication", SH_VND_ID, &g_pua_cmd.pua_service_indication);
|
||||
SEARCH_AVP_("Sequence-Number", SH_VND_ID, &g_pua_cmd.pua_sequence_number);
|
||||
|
||||
SEARCH_AVP_("Data-Reference", SH_VND_ID, &g_pua_cmd.pua_data_reference);
|
||||
|
||||
SEARCH_AVP_("Supported-Features", SH_VND_ID, &g_pua_cmd.pua_supported_features );
|
||||
SEARCH_AVP_("Feature-List-ID", SH_VND_ID, &g_pua_cmd.pua_feature_list_id);
|
||||
SEARCH_AVP_("Feature-List", SH_VND_ID, &g_pua_cmd.pua_feature_list);
|
||||
|
||||
SEARCH_AVP_("OC-Supported-Features", SH_VND_ID, &g_pua_cmd.pua_oc_supported_features );
|
||||
SEARCH_AVP_("OC-Feature-Vector", SH_VND_ID, &g_pua_cmd.pua_oc_feature_vector);
|
||||
|
||||
SEARCH_AVP_("OC-OLR", SH_VND_ID, &g_pua_cmd.pua_oc_olr );
|
||||
SEARCH_AVP_("OC-Sequence-Number", SH_VND_ID, &g_pua_cmd.pua_oc_sequence_number);
|
||||
SEARCH_AVP_("OC-Report-Type", SH_VND_ID, &g_pua_cmd.pua_oc_report_type);
|
||||
SEARCH_AVP_("OC-Reduction-Percentage", SH_VND_ID, &g_pua_cmd.pua_oc_reduction_percentage);
|
||||
SEARCH_AVP_("OC-Validity-Duration", SH_VND_ID, &g_pua_cmd.pua_oc_validity_duration);
|
||||
|
||||
/* Session-Id */
|
||||
PARSE_AVP_STR(pua_msg, g_pua_cmd.pua_session_id, avp, avphdr, "ession-Id", avphdr->avp_value->os.data)
|
||||
|
||||
/* DRMP */
|
||||
PARSE_AVP_U32(pua_msg, g_pua_cmd.pua_drmp, avp, avphdr, "DRMP", avphdr->avp_value->u32)
|
||||
|
||||
/* Vendor-Specific-Application-Id */
|
||||
CHECK_FCT( fd_msg_search_avp ( pua_msg, g_pua_cmd.pua_vendor_specific_application_id, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj Vendor-Specific-Application-Id");
|
||||
|
||||
/* Vendor-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pua_cmd.pua_vendor_id, avp, avphdr, "Vendor-Id", avphdr->avp_value->u32)
|
||||
|
||||
/* Auth-Application-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pua_cmd.pua_auth_application_d, avp, avphdr, "Auth-Application-Id", avphdr->avp_value->u32)
|
||||
|
||||
/* Acct-Application-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pua_cmd.pua_acct_application_id, avp, avphdr, "Acct-Application-Id", avphdr->avp_value->u32)
|
||||
}
|
||||
|
||||
/* Result-Code */
|
||||
PARSE_AVP_U32(pua_msg, g_pua_cmd.pua_result_code, avp, avphdr, "Result-Code", avphdr->avp_value->u32)
|
||||
|
||||
/* Experimental-Result */
|
||||
CHECK_FCT( fd_msg_search_avp ( pua_msg, g_pua_cmd.pua_experimental_result, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj Experimental-Result");
|
||||
|
||||
/* Vendor-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pua_cmd.pua_vendor_id, avp, avphdr, "Vendor-Id", avphdr->avp_value->u32)
|
||||
|
||||
/* Experimental-Result-Code */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pua_cmd.pua_experimental_result_code, avp, avphdr, "Experimental-Result-Code", avphdr->avp_value->u32)
|
||||
}
|
||||
|
||||
/* Auth-Session-State */
|
||||
PARSE_AVP_U32(pua_msg, g_pua_cmd.pua_auth_session_state, avp, avphdr, "Auth-Session-State", avphdr->avp_value->u32)
|
||||
|
||||
|
||||
/* Origin-Host */
|
||||
PARSE_AVP_STR(pua_msg, g_pua_cmd.pua_origin_host, avp, avphdr, "Origin-Host", avphdr->avp_value->os.data)
|
||||
|
||||
/* Origin-Realm */
|
||||
PARSE_AVP_STR(pua_msg, g_pua_cmd.pua_origin_realm, avp, avphdr, "Origin-Realm", avphdr->avp_value->os.data)
|
||||
|
||||
|
||||
/* Wildcarded-Public-Identity */
|
||||
PARSE_AVP_STR(pua_msg, g_pua_cmd.pua_wildcarded_public_identity, avp, avphdr, "Wildcarded-Public-Identity", avphdr->avp_value->os.data)
|
||||
|
||||
/* Wildcarded-IMPU */
|
||||
PARSE_AVP_STR(pua_msg, g_pua_cmd.pua_wildcarded_impu, avp, avphdr, "Wildcarded-IMPU", avphdr->avp_value->os.data)
|
||||
|
||||
/* Repository-Data-ID */
|
||||
CHECK_FCT( fd_msg_search_avp ( pua_msg, g_pua_cmd.pua_repository_data_id, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj Repository-Data-ID");
|
||||
|
||||
/* Service-Indication */
|
||||
PARSE_GRPAVP_STR(grpavp, g_pua_cmd.pua_service_indication, avp, avphdr, "Service-Indication", avphdr->avp_value->os.data)
|
||||
|
||||
/* Sequence-Number */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pua_cmd.pua_sequence_number, avp, avphdr, "Sequence-Number", avphdr->avp_value->u32)
|
||||
}
|
||||
|
||||
/* Data-Reference */
|
||||
PARSE_AVP_U32(pua_msg, g_pua_cmd.pua_data_reference, avp, avphdr, "Data-Reference", avphdr->avp_value->u32)
|
||||
|
||||
/* Supported-Features */
|
||||
CHECK_FCT( fd_msg_search_avp ( pua_msg, g_pua_cmd.pua_supported_features, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj Supported-Features");
|
||||
|
||||
/* Vendor-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pua_cmd.pua_vendor_id, avp, avphdr, "Vendor-Id", avphdr->avp_value->u32)
|
||||
|
||||
/* Feature-List-ID */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pua_cmd.pua_feature_list_id, avp, avphdr, "Feature-List-ID", avphdr->avp_value->u32)
|
||||
|
||||
/* Feature-List */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pua_cmd.pua_feature_list, avp, avphdr, "Feature-List", avphdr->avp_value->u32)
|
||||
}
|
||||
|
||||
/* OC-Supported-Features */
|
||||
CHECK_FCT( fd_msg_search_avp ( pua_msg, g_pua_cmd.pua_oc_supported_features, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj OC-Supported-Features");
|
||||
|
||||
/* OC-Feature-Vector */
|
||||
PARSE_GRPAVP_U64(grpavp, g_pua_cmd.pua_oc_feature_vector, avp, avphdr, "OC-Feature-Vector", avphdr->avp_value->u64)
|
||||
}
|
||||
|
||||
/* OC-OLR */
|
||||
CHECK_FCT( fd_msg_search_avp ( pua_msg, g_pua_cmd.pua_oc_olr, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj OC-OLR");
|
||||
|
||||
/* OC-Sequence-Number */
|
||||
PARSE_GRPAVP_U64(grpavp, g_pua_cmd.pua_oc_feature_vector, avp, avphdr, "OC-Sequence-Number", avphdr->avp_value->u64)
|
||||
|
||||
/* OC-Report-Type */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pua_cmd.pua_oc_report_type, avp, avphdr, "OC-Report-Type", avphdr->avp_value->u32)
|
||||
|
||||
/* OC-Reduction-Percentage */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pua_cmd.pua_oc_reduction_percentage, avp, avphdr, "OC-Reduction-Percentage", avphdr->avp_value->u32)
|
||||
|
||||
/* OC-Validity-Duration */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pua_cmd.pua_oc_validity_duration, avp, avphdr, "OC-Validity-Duration", avphdr->avp_value->u32)
|
||||
|
||||
}
|
||||
|
||||
out:
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int sh_parse_uda(struct msg** msg)
|
||||
{
|
||||
struct msg* udr_msg = *msg;
|
||||
struct avp *avp, *grpavp=NULL;
|
||||
struct avp_hdr *avphdr;
|
||||
|
||||
LOG_D("fj sh_parse_uda");
|
||||
|
||||
SEARCH_AVP_("Origin-Host", 0, &g_uda_cmd.uda_origin_host);
|
||||
SEARCH_AVP_("Session-Id", 0, &g_uda_cmd.uda_session_id);
|
||||
SEARCH_AVP_("DRMP", SH_VND_ID, &g_uda_cmd.uda_drmp);
|
||||
SEARCH_AVP_("Vendor-Specific-Application-Id", 0, &g_uda_cmd.uda_vendor_specific_application_id);
|
||||
SEARCH_AVP_("Vendor-Id", 0, &g_uda_cmd.uda_vendor_id);
|
||||
SEARCH_AVP_("Auth-Application-Id", 0, &g_uda_cmd.uda_auth_application_d);
|
||||
SEARCH_AVP_("Acct-Application-Id", 0, &g_uda_cmd.uda_acct_application_id);
|
||||
|
||||
|
||||
SEARCH_AVP_("Result-Code", 0, &g_uda_cmd.uda_result_code);
|
||||
|
||||
SEARCH_AVP_("Experimental-Result", 0, &g_uda_cmd.uda_experimental_result);
|
||||
SEARCH_AVP_("Experimental-Result-Code", 0, &g_uda_cmd.uda_experimental_result_code);
|
||||
|
||||
SEARCH_AVP_("Auth-Session-State", 0, &g_uda_cmd.uda_auth_session_state);
|
||||
|
||||
SEARCH_AVP_("Origin-Realm", 0, &g_uda_cmd.uda_origin_realm);
|
||||
|
||||
SEARCH_AVP_("Supported-Features", SH_VND_ID, &g_uda_cmd.uda_supported_features );
|
||||
SEARCH_AVP_("Feature-List-ID", SH_VND_ID, &g_uda_cmd.uda_feature_list_id);
|
||||
SEARCH_AVP_("Feature-List", SH_VND_ID, &g_uda_cmd.uda_feature_list);
|
||||
|
||||
|
||||
SEARCH_AVP_("Wildcarded-Public-Identity", SH_VND_ID, &g_uda_cmd.uda_wildcarded_public_identity );
|
||||
SEARCH_AVP_("Wildcarded-IMPU", SH_VND_ID, &g_uda_cmd.uda_wildcarded_impu );
|
||||
SEARCH_AVP_("User-Data", SH_VND_ID, &g_uda_cmd.uda_user_data );
|
||||
|
||||
SEARCH_AVP_("OC-Supported-Features", SH_VND_ID, &g_uda_cmd.uda_oc_supported_features );
|
||||
// SEARCH_AVP_("OC-Feature-Vector", SH_VND_ID, &g_uda_cmd.uda_oc_feature_vector);
|
||||
|
||||
SEARCH_AVP_("OC-OLR", SH_VND_ID, &g_uda_cmd.uda_oc_olr );
|
||||
SEARCH_AVP_("OC-Sequence-Number", SH_VND_ID, &g_uda_cmd.uda_oc_sequence_number);
|
||||
SEARCH_AVP_("OC-Report-Type", SH_VND_ID, &g_uda_cmd.uda_oc_report_type);
|
||||
SEARCH_AVP_("OC-Reduction-Percentage", SH_VND_ID, &g_uda_cmd.uda_oc_reduction_percentage);
|
||||
SEARCH_AVP_("OC-Validity-Duration", SH_VND_ID, &g_uda_cmd.uda_oc_validity_duration);
|
||||
|
||||
/* Session-Id */
|
||||
PARSE_AVP_STR(udr_msg, g_uda_cmd.uda_session_id, avp, avphdr, "Session-Id", avphdr->avp_value->os.data)
|
||||
|
||||
/* DRMP */
|
||||
PARSE_AVP_U32(udr_msg, g_uda_cmd.uda_drmp, avp, avphdr, "DRMP", avphdr->avp_value->u32)
|
||||
|
||||
/* Vendor-Specific-Application-Id */
|
||||
CHECK_FCT( fd_msg_search_avp ( udr_msg, g_uda_cmd.uda_vendor_specific_application_id, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj Vendor-Specific-Application-Id");
|
||||
|
||||
/* Vendor-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_uda_cmd.uda_vendor_id, avp, avphdr, "Vendor-Id", avphdr->avp_value->u32)
|
||||
|
||||
/* Auth-Application-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_uda_cmd.uda_auth_application_d, avp, avphdr, "Auth-Application-Id", avphdr->avp_value->u32)
|
||||
|
||||
/* Acct-Application-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_uda_cmd.uda_acct_application_id, avp, avphdr, "Acct-Application-Id", avphdr->avp_value->u32)
|
||||
}
|
||||
|
||||
/* Result-Code */
|
||||
PARSE_AVP_U32(udr_msg, g_uda_cmd.uda_result_code, avp, avphdr, "Result-Code", avphdr->avp_value->u32)
|
||||
|
||||
/* Experimental-Result */
|
||||
CHECK_FCT( fd_msg_search_avp ( udr_msg, g_uda_cmd.uda_experimental_result, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj Experimental-Result");
|
||||
|
||||
/* Vendor-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_uda_cmd.uda_vendor_id, avp, avphdr, "Vendor-Id", avphdr->avp_value->u32)
|
||||
|
||||
/* Experimental-Result-Code */
|
||||
PARSE_GRPAVP_U32(grpavp, g_uda_cmd.uda_experimental_result_code, avp, avphdr, "Experimental-Result-Code", avphdr->avp_value->u32)
|
||||
}
|
||||
|
||||
/* Auth-Session-State */
|
||||
PARSE_AVP_U32(udr_msg, g_uda_cmd.uda_auth_session_state, avp, avphdr, "Auth-Session-State", avphdr->avp_value->u32)
|
||||
|
||||
|
||||
/* Origin-Host */
|
||||
PARSE_AVP_STR(udr_msg, g_uda_cmd.uda_origin_host, avp, avphdr, "Origin-Host", avphdr->avp_value->os.data)
|
||||
|
||||
/* Origin-Realm */
|
||||
PARSE_AVP_STR(udr_msg, g_uda_cmd.uda_origin_realm, avp, avphdr, "Origin-Realm", avphdr->avp_value->os.data)
|
||||
|
||||
/* Supported-Features */
|
||||
CHECK_FCT( fd_msg_search_avp ( udr_msg, g_uda_cmd.uda_supported_features, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj Supported-Features");
|
||||
|
||||
/* Vendor-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_uda_cmd.uda_vendor_id, avp, avphdr, "Vendor-Id", avphdr->avp_value->u32)
|
||||
|
||||
/* Feature-List-ID */
|
||||
PARSE_GRPAVP_U32(grpavp, g_uda_cmd.uda_feature_list_id, avp, avphdr, "Feature-List-ID", avphdr->avp_value->u32)
|
||||
|
||||
/* Feature-List */
|
||||
PARSE_GRPAVP_U32(grpavp, g_uda_cmd.uda_feature_list, avp, avphdr, "Feature-List", avphdr->avp_value->u32)
|
||||
}
|
||||
|
||||
/* Wildcarded-Public-Identity */
|
||||
PARSE_AVP_STR(udr_msg, g_uda_cmd.uda_wildcarded_public_identity, avp, avphdr, "Wildcarded-Public-Identity", avphdr->avp_value->os.data)
|
||||
|
||||
/* Wildcarded-IMPU */
|
||||
PARSE_AVP_STR(udr_msg, g_uda_cmd.uda_wildcarded_impu, avp, avphdr, "Wildcarded-IMPU", avphdr->avp_value->os.data)
|
||||
|
||||
/* User-Data */
|
||||
PARSE_AVP_STR(udr_msg, g_uda_cmd.uda_user_data, avp, avphdr, "User-Data", avphdr->avp_value->os.data)
|
||||
|
||||
|
||||
/* OC-Supported-Features */
|
||||
CHECK_FCT( fd_msg_search_avp ( udr_msg, g_uda_cmd.uda_oc_supported_features, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj OC-Supported-Features");
|
||||
|
||||
/* OC-Feature-Vector */
|
||||
// PARSE_GRPAVP_U32(grpavp, g_uda_cmd.uda_oc_feature_vector, avp, avphdr, "OC-Feature-Vector", avphdr->avp_value->u64)
|
||||
}
|
||||
|
||||
/* OC-OLR */
|
||||
CHECK_FCT( fd_msg_search_avp ( udr_msg, g_uda_cmd.uda_oc_olr, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj OC-OLR");
|
||||
|
||||
/* OC-Sequence-Number */
|
||||
PARSE_GRPAVP_U64(grpavp, g_uda_cmd.uda_oc_sequence_number, avp, avphdr, "OC-Sequence-Number", avphdr->avp_value->u64)
|
||||
|
||||
/* OC-Report-Type */
|
||||
PARSE_GRPAVP_U32(grpavp, g_uda_cmd.uda_oc_report_type, avp, avphdr, "OC-Report-Type", avphdr->avp_value->u32)
|
||||
|
||||
/* OC-Reduction-Percentage */
|
||||
PARSE_GRPAVP_U32(grpavp, g_uda_cmd.uda_oc_reduction_percentage, avp, avphdr, "OC-Reduction-Percentage", avphdr->avp_value->u32)
|
||||
|
||||
/* OC-Validity-Duration */
|
||||
PARSE_GRPAVP_U32(grpavp, g_uda_cmd.uda_oc_validity_duration, avp, avphdr, "OC-Validity-Duration", avphdr->avp_value->u32)
|
||||
}
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Cb called when an answer is received */
|
||||
static int sh_rec_pua( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act)
|
||||
{
|
||||
LOG_D("fj sh_rec_pua in");
|
||||
|
||||
fprintf(stderr, "ECHO PUA received from 'server.domain', done...\n");
|
||||
|
||||
sh_parse_pua(msg);
|
||||
|
||||
/* Free the message */
|
||||
CHECK_FCT_DO(fd_msg_free(*msg), return 0);
|
||||
*msg = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sh_rec_uda( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act)
|
||||
{
|
||||
LOG_D("fj sh_rec_uda in\n");
|
||||
|
||||
fprintf(stderr, "ECHO UDA received from 'server.domain', replying...\n");
|
||||
|
||||
sh_parse_uda(msg);
|
||||
|
||||
// sh_send_pur();
|
||||
|
||||
/* Free the message */
|
||||
CHECK_FCT_DO(fd_msg_free(*msg), return 0);
|
||||
*msg = NULL;
|
||||
|
||||
return 0;
|
||||
#if 0
|
||||
struct sess_state * mi = NULL;
|
||||
struct timespec ts;
|
||||
struct session * sess;
|
||||
struct avp * avp;
|
||||
struct avp_hdr * hdr;
|
||||
unsigned long dur;
|
||||
int error = 0;
|
||||
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), return );
|
||||
|
||||
/* Search the session, retrieve its data */
|
||||
{
|
||||
int new;
|
||||
CHECK_FCT_DO( fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &sess, &new), return );
|
||||
ASSERT( new == 0 );
|
||||
|
||||
CHECK_FCT_DO( fd_sess_state_retrieve( sh_cli_reg, sess, &mi ), return );
|
||||
ASSERT( (void *)mi == data );
|
||||
}
|
||||
|
||||
/* Now log content of the answer */
|
||||
fprintf(stderr, "RECV ");
|
||||
|
||||
/* Value of Test-AVP */
|
||||
CHECK_FCT_DO( fd_msg_search_avp ( *msg, ta_avp, &avp), return );
|
||||
if (avp) {
|
||||
CHECK_FCT_DO( fd_msg_avp_hdr( avp, &hdr ), return );
|
||||
if (hdr->avp_value->i32 == mi->randval) {
|
||||
fprintf(stderr, "%x (%s) ", hdr->avp_value->i32, "Ok");
|
||||
} else {
|
||||
fprintf(stderr, "%x (%s) ", hdr->avp_value->i32, "PROBLEM");
|
||||
error++;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "no_Test-AVP ");
|
||||
error++;
|
||||
}
|
||||
|
||||
/* Value of Result Code */
|
||||
CHECK_FCT_DO( fd_msg_search_avp ( *msg, ta_res_code, &avp), return );
|
||||
if (avp) {
|
||||
CHECK_FCT_DO( fd_msg_avp_hdr( avp, &hdr ), return );
|
||||
fprintf(stderr, "Status: %d ", hdr->avp_value->i32);
|
||||
if (hdr->avp_value->i32 != 2001)
|
||||
error++;
|
||||
} else {
|
||||
fprintf(stderr, "no_Result-Code ");
|
||||
error++;
|
||||
}
|
||||
|
||||
/* Value of Origin-Host */
|
||||
CHECK_FCT_DO( fd_msg_search_avp ( *msg, ta_origin_host, &avp), return );
|
||||
if (avp) {
|
||||
CHECK_FCT_DO( fd_msg_avp_hdr( avp, &hdr ), return );
|
||||
fprintf(stderr, "From '%.*s' ", (int)hdr->avp_value->os.len, hdr->avp_value->os.data);
|
||||
} else {
|
||||
fprintf(stderr, "no_Origin-Host ");
|
||||
error++;
|
||||
}
|
||||
|
||||
/* Value of Origin-Realm */
|
||||
CHECK_FCT_DO( fd_msg_search_avp ( *msg, ta_origin_realm, &avp), return );
|
||||
if (avp) {
|
||||
CHECK_FCT_DO( fd_msg_avp_hdr( avp, &hdr ), return );
|
||||
fprintf(stderr, "('%.*s') ", (int)hdr->avp_value->os.len, hdr->avp_value->os.data);
|
||||
} else {
|
||||
fprintf(stderr, "no_Origin-Realm ");
|
||||
error++;
|
||||
}
|
||||
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), );
|
||||
dur = ((ts.tv_sec - mi->ts.tv_sec) * 1000000) + ((ts.tv_nsec - mi->ts.tv_nsec) / 1000);
|
||||
if (ta_conf->stats.nb_recv) {
|
||||
/* Ponderate in the avg */
|
||||
ta_conf->stats.avg = (ta_conf->stats.avg * ta_conf->stats.nb_recv + dur) / (ta_conf->stats.nb_recv + 1);
|
||||
/* Min, max */
|
||||
if (dur < ta_conf->stats.shortest)
|
||||
ta_conf->stats.shortest = dur;
|
||||
if (dur > ta_conf->stats.longest)
|
||||
ta_conf->stats.longest = dur;
|
||||
} else {
|
||||
ta_conf->stats.shortest = dur;
|
||||
ta_conf->stats.longest = dur;
|
||||
ta_conf->stats.avg = dur;
|
||||
}
|
||||
|
||||
if (error)
|
||||
ta_conf->stats.nb_errs++;
|
||||
else
|
||||
ta_conf->stats.nb_recv++;
|
||||
|
||||
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), );
|
||||
|
||||
/* Display how long it took */
|
||||
if (ts.tv_nsec > mi->ts.tv_nsec) {
|
||||
fprintf(stderr, "in %d.%06ld sec",
|
||||
(int)(ts.tv_sec - mi->ts.tv_sec),
|
||||
(long)(ts.tv_nsec - mi->ts.tv_nsec) / 1000);
|
||||
} else {
|
||||
fprintf(stderr, "in %d.%06ld sec",
|
||||
(int)(ts.tv_sec + 1 - mi->ts.tv_sec),
|
||||
(long)(1000000000 + ts.tv_nsec - mi->ts.tv_nsec) / 1000);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
|
||||
/* Free the message */
|
||||
CHECK_FCT_DO(fd_msg_free(*msg), return);
|
||||
*msg = NULL;
|
||||
|
||||
free(mi);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void sh_send_entry()
|
||||
{
|
||||
static int i = 0;
|
||||
|
||||
if((++i)%2)
|
||||
sh_send_udr();
|
||||
else
|
||||
sh_send_pur();
|
||||
}
|
||||
#endif
|
||||
/* Default callback for the application. */
|
||||
#if 0
|
||||
static int ta_fb_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act)
|
||||
{
|
||||
/* This CB should never be called */
|
||||
TRACE_ENTRY("%p %p %p %p", msg, avp, sess, act);
|
||||
|
||||
fd_log_debug("Unexpected message received!");
|
||||
|
||||
return ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
|
||||
int sh_cli_init(void)
|
||||
{
|
||||
CHECK_FCT( fd_sess_handler_create(&sh_cli_reg, (void *)free, NULL, NULL) );
|
||||
|
||||
/* fj added */
|
||||
{
|
||||
struct disp_when data;
|
||||
|
||||
LOG_D("Initializing dispatch callbacks for test");
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.app = sh_appli;
|
||||
data.command = uda_cmd;
|
||||
|
||||
/* Now specific handler for UDR */
|
||||
CHECK_FCT( fd_disp_register( sh_rec_uda, DISP_HOW_CC, &data, NULL, &sh_hdl_uda ) );
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.app = sh_appli;
|
||||
data.command = pua_cmd;
|
||||
/* Now specific handler for PUR */
|
||||
CHECK_FCT( fd_disp_register( sh_rec_pua, DISP_HOW_CC, &data, NULL, &sh_hdl_pua ) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sh_cli_finit(void)
|
||||
{
|
||||
CHECK_FCT_DO( fd_sess_handler_destroy(&sh_cli_reg, NULL), /* continue */ );
|
||||
|
||||
/* fj added */
|
||||
if (sh_hdl_uda) {
|
||||
(void) fd_disp_unregister(&sh_hdl_uda, NULL);
|
||||
}
|
||||
|
||||
if (sh_hdl_pua) {
|
||||
(void) fd_disp_unregister(&sh_hdl_pua, NULL);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
371
plat/diameter/extensions/sh_app/sh_conf.c
Normal file
371
plat/diameter/extensions/sh_app/sh_conf.c
Normal file
@@ -0,0 +1,371 @@
|
||||
#include "sh_conf.h"
|
||||
|
||||
Ro_LinkSet rolkset={0,0};
|
||||
|
||||
int GetRoDiamIdPeer(DiamId_t **realm, DiamId_t **host, int bSms)
|
||||
{
|
||||
struct peer_hdr*peer = NULL;
|
||||
SH_CONF_S *pcfg = NULL;
|
||||
int i;
|
||||
int ret = -1;
|
||||
int peer_state = -1;
|
||||
if (bSms)
|
||||
{
|
||||
int curlk = rolkset.cursmslk;
|
||||
for (i=0; i<rolkset.smslknum; i++)
|
||||
{
|
||||
curlk = (curlk + i +1) % rolkset.smslknum;
|
||||
pcfg = &rolkset.smslk[curlk].cfg;
|
||||
if (pcfg->pi_diamid_peer != NULL)
|
||||
{
|
||||
ret = fd_peer_getbyid(pcfg->pi_diamid_peer, strlen(pcfg->pi_diamid_peer), 0, &peer);
|
||||
if( !ret && peer )
|
||||
{
|
||||
peer_state = fd_peer_get_state(peer);
|
||||
if( STATE_OPEN == peer_state )
|
||||
{
|
||||
if (rolkset.smslk[curlk].bconn == 0)
|
||||
{
|
||||
printf("diam peer disconn to conn, host[%s]\r\n", pcfg->pi_diamid_peer);
|
||||
rolkset.smslk[curlk].bconn = 1;
|
||||
}
|
||||
*realm = pcfg->pi_diamid_realm_peer;
|
||||
*host = pcfg->pi_diamid_peer;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rolkset.smslk[curlk].bconn == 1)
|
||||
{
|
||||
printf("diam peer conn to discon, host[%s]\r\n", pcfg->pi_diamid_peer);
|
||||
rolkset.smslk[curlk].bconn = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("diam peer NA, host[%s], ret[%d], peer[%p]\r\n", pcfg->pi_diamid_peer, ret, peer);
|
||||
rolkset.smslk[curlk].bconn = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int curlk = rolkset.curvoicelk;
|
||||
for (i=0; i<rolkset.voicelknum; i++)
|
||||
{
|
||||
curlk = (curlk + i +1) % rolkset.voicelknum;
|
||||
pcfg = &rolkset.voicelk[curlk].cfg;
|
||||
if (pcfg->pi_diamid_peer != NULL)
|
||||
{
|
||||
ret = fd_peer_getbyid(pcfg->pi_diamid_peer, strlen(pcfg->pi_diamid_peer), 0, &peer);
|
||||
if( !ret && peer )
|
||||
{
|
||||
peer_state = fd_peer_get_state(peer);
|
||||
if( STATE_OPEN == peer_state )
|
||||
{
|
||||
if (rolkset.voicelk[curlk].bconn == 0)
|
||||
{
|
||||
printf("diam peer disconn to conn, host[%s]\r\n", pcfg->pi_diamid_peer);
|
||||
rolkset.voicelk[curlk].bconn = 1;
|
||||
}
|
||||
*realm = pcfg->pi_diamid_realm_peer;
|
||||
*host = pcfg->pi_diamid_peer;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rolkset.voicelk[curlk].bconn == 1)
|
||||
{
|
||||
printf("diam peer conn to discon, host[%s]\r\n", pcfg->pi_diamid_peer);
|
||||
rolkset.voicelk[curlk].bconn = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("diam peer NA, host[%s], ret[%d], peer[%p]\r\n", pcfg->pi_diamid_peer, ret, peer);
|
||||
rolkset.voicelk[curlk].bconn = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AddRoLink(SH_CONF_S *cfg, uint16_t port, int bSms)
|
||||
{
|
||||
if (bSms)
|
||||
{
|
||||
if(rolkset.smslknum >= MaxRoLinkNum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
rolkset.smslk[rolkset.smslknum].cfg.pi_diamid_peer = strdup(cfg->pi_diamid_peer);
|
||||
rolkset.smslk[rolkset.smslknum].cfg.pi_diamid_realm_peer = strdup(cfg->pi_diamid_realm_peer);
|
||||
rolkset.smslk[rolkset.smslknum].cfg.peer_port = port;
|
||||
rolkset.smslknum++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(rolkset.voicelknum >= MaxRoLinkNum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
rolkset.voicelk[rolkset.voicelknum].cfg.pi_diamid_peer = strdup(cfg->pi_diamid_peer);
|
||||
rolkset.voicelk[rolkset.voicelknum].cfg.pi_diamid_realm_peer = strdup(cfg->pi_diamid_realm_peer);
|
||||
rolkset.voicelk[rolkset.voicelknum].cfg.peer_port = port;
|
||||
rolkset.voicelknum++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
SH_CONF_S g_sh_conf_ext;
|
||||
//SH_CONF_S g_rovoice_conf_ext;
|
||||
//SH_CONF_S g_rosms_conf_ext;
|
||||
|
||||
#define SH_PARSE_BUFFER_LEN 1024
|
||||
|
||||
static char* shParseStr_(char* buffer, char* _key, char *ret_str, int flag_from_begin)
|
||||
{
|
||||
char *pos = strstr(buffer, _key);
|
||||
char *pos_1 = NULL;
|
||||
char *pos_2 = NULL;
|
||||
if(NULL != pos && (flag_from_begin ? (buffer == pos) : 1) )
|
||||
{
|
||||
pos_1 = strstr(pos, "\"");
|
||||
if(NULL != pos_1)
|
||||
{
|
||||
pos_2 = strstr(pos_1 + 1, "\"");
|
||||
if(NULL != pos_2)
|
||||
{
|
||||
memcpy(ret_str, pos_1 + 1, pos_2 - pos_1 - 1);
|
||||
ret_str[pos_2 - pos_1] = '\0';
|
||||
// fprintf(stderr, "%s=%s\n", _key, ret_str);
|
||||
return ret_str;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char* shParseStr(char* buffer, char* _key, char *ret_str)
|
||||
{
|
||||
return shParseStr_(buffer, _key, ret_str, 1);
|
||||
}
|
||||
static char* shParseStrSub(char* buffer, char* _key, char *ret_str)
|
||||
{
|
||||
return shParseStr_(buffer, _key, ret_str, 0);
|
||||
}
|
||||
|
||||
uint16_t shParseInt(char* buffer, char* _key, uint16_t* ret_int)
|
||||
{
|
||||
char buff_num[16] = {0};
|
||||
|
||||
char *pos = strstr(buffer, _key);
|
||||
char *pos_1 = NULL;
|
||||
char *pos_2 = NULL;
|
||||
/* first address is start of the line */
|
||||
if(NULL != pos && buffer == pos)
|
||||
{
|
||||
pos_1 = strstr(pos, "=");
|
||||
if(NULL != pos_1)
|
||||
{
|
||||
pos_2 = strstr(pos_1 + 1, ";");
|
||||
if(NULL != pos_2)
|
||||
{
|
||||
memcpy(buff_num, pos_1 + 1, pos_2 - pos_1 - 1);
|
||||
*ret_int = atol( buff_num );
|
||||
// fprintf(stderr, "%s=%d\n", _key, *ret_int);
|
||||
return *ret_int;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int shParseFlags(char* buffer, char* _key, char* no_flag_key)
|
||||
{
|
||||
char *pos = strstr(buffer, _key);
|
||||
char *pos_1 = NULL;
|
||||
char *pos_2 = NULL;
|
||||
/* first address is start of the line */
|
||||
if(NULL != pos && buffer == pos)
|
||||
{
|
||||
pos_1 = strstr(pos, "{");
|
||||
if(NULL != pos_1)
|
||||
{
|
||||
pos_2 = strstr(pos_1 + 1, "}");
|
||||
if(NULL != pos_2)
|
||||
{
|
||||
if(strstr( pos_1 + 1, no_flag_key) )
|
||||
{
|
||||
// fprintf(stderr, "%s\n", no_flag_key);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int shParse_(struct fd_config * conf)
|
||||
{
|
||||
FILE* fd;
|
||||
char buffer[SH_PARSE_BUFFER_LEN] = {0};
|
||||
char ret_str[512] = {0};
|
||||
|
||||
/* Create input file descriptor */
|
||||
fd = fopen (conf->cnf_file, "r");
|
||||
if (fd == NULL)
|
||||
{
|
||||
perror ("open");
|
||||
return 2;
|
||||
}
|
||||
|
||||
conf->ro_voiceport = 29100;
|
||||
conf->ro_smsport = 19500;
|
||||
strcpy(conf->service_context_voice, "agrandtech_ro@3gpp.org");
|
||||
strcpy(conf->service_context_sms, "agrandtech_sms@3gpp.org");
|
||||
/* Copy process */
|
||||
while((fgets(buffer, SH_PARSE_BUFFER_LEN, fd)) != NULL)
|
||||
{
|
||||
if( shParseStr(buffer, "Identity", ret_str) )
|
||||
{
|
||||
conf->cnf_diamid = strdup(ret_str);
|
||||
conf->cnf_diamid_len = strlen(ret_str);
|
||||
|
||||
memset( ret_str, 0, strlen(ret_str) );
|
||||
}
|
||||
if( shParseStr(buffer, "Realm", ret_str) )
|
||||
{
|
||||
conf->cnf_diamrlm = strdup(ret_str);
|
||||
conf->cnf_diamrlm_len = strlen(ret_str);
|
||||
|
||||
memset( ret_str, 0, strlen(ret_str) );
|
||||
}
|
||||
if( shParseStr(buffer, "ServiceCxtRoVoice", ret_str) )
|
||||
{
|
||||
strcpy(conf->service_context_voice, ret_str);
|
||||
memset( ret_str, 0, strlen(ret_str) );
|
||||
}
|
||||
if( shParseStr(buffer, "ServiceCxtRoSms", ret_str) )
|
||||
{
|
||||
strcpy(conf->service_context_sms, ret_str);
|
||||
memset( ret_str, 0, strlen(ret_str) );
|
||||
}
|
||||
shParseInt(buffer, "RoVoicePort", &conf->ro_voiceport);
|
||||
shParseInt(buffer, "RoSmsPort", &conf->ro_smsport);
|
||||
shParseInt(buffer, "Port", &conf->cnf_port);
|
||||
shParseInt(buffer, "SecPort", &conf->cnf_port_tls);
|
||||
shParseInt(buffer, "SCTPStr", &conf->cnf_sctp_str);
|
||||
|
||||
if( shParseFlags(buffer, "ConnectPeer", "No_TLS") )
|
||||
{
|
||||
conf->cnf_sec_data.tls_disabled = 1;
|
||||
}
|
||||
if( shParseFlags(buffer, "ConnectPeer", "No_FWD") )
|
||||
{
|
||||
conf->cnf_flags.no_fwd = 1;
|
||||
}
|
||||
if( shParseFlags(buffer, "ConnectPeer", "No_IP4") )
|
||||
{
|
||||
conf->cnf_flags.no_ip4 = 1;
|
||||
}
|
||||
if( shParseFlags(buffer, "ConnectPeer", "No_IP6") )
|
||||
{
|
||||
conf->cnf_flags.no_ip6 = 1;
|
||||
}
|
||||
if( shParseFlags(buffer, "ConnectPeer", "No_TCP") )
|
||||
{
|
||||
conf->cnf_flags.no_tcp = 1;
|
||||
}
|
||||
if( shParseFlags(buffer, "ConnectPeer", "No_SCTP") )
|
||||
{
|
||||
conf->cnf_flags.no_sctp = 1;
|
||||
}
|
||||
if( shParseFlags(buffer, "ConnectPeer", "Prefer_TCP") )
|
||||
{
|
||||
conf->cnf_flags.pr_tcp = 1;
|
||||
}
|
||||
|
||||
memset(buffer, 0, SH_PARSE_BUFFER_LEN);
|
||||
}
|
||||
|
||||
fclose (fd);
|
||||
|
||||
conf->cnf_flags.tls_alg = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int shParseExt(struct fd_config * conf)
|
||||
{
|
||||
FILE* fd;
|
||||
char buffer[SH_PARSE_BUFFER_LEN] = {0};
|
||||
char ret_str[512] = {0};
|
||||
|
||||
fd = fopen (conf->cnf_file, "r");
|
||||
if(NULL == fd)
|
||||
{
|
||||
perror ("open");
|
||||
return 2;
|
||||
}
|
||||
|
||||
while((fgets(buffer, SH_PARSE_BUFFER_LEN, fd)) != NULL)
|
||||
{
|
||||
shParseInt( buffer, "ServiceMod", (uint16_t*)(&g_sh_conf_ext.mode) );
|
||||
|
||||
if( shParseStr(buffer, "ConnectPeer", ret_str) )
|
||||
{
|
||||
g_sh_conf_ext.pi_diamid_peer = strdup(ret_str);
|
||||
memset( ret_str, 0, strlen(ret_str) );
|
||||
|
||||
if( shParseStrSub(buffer, "Realm", ret_str) )
|
||||
{
|
||||
g_sh_conf_ext.pi_diamid_realm_peer = strdup(ret_str);
|
||||
memset( ret_str, 0, strlen(ret_str) );
|
||||
}
|
||||
g_sh_conf_ext.peer_port = fd_g_config->cnf_port;
|
||||
if( shParseFlags(buffer, "ConnectPeer", "Ro_SMS") )
|
||||
{
|
||||
//g_rosms_conf_ext.pi_diamid_peer = strdup(g_sh_conf_ext.pi_diamid_peer);
|
||||
//g_rosms_conf_ext.pi_diamid_realm_peer = strdup(g_sh_conf_ext.pi_diamid_realm_peer);
|
||||
//g_rosms_conf_ext.peer_port = fd_g_config->ro_smsport;
|
||||
AddRoLink(&g_sh_conf_ext, fd_g_config->ro_smsport, 1);
|
||||
free(g_sh_conf_ext.pi_diamid_peer);
|
||||
g_sh_conf_ext.pi_diamid_peer = NULL;
|
||||
free(g_sh_conf_ext.pi_diamid_realm_peer);
|
||||
g_sh_conf_ext.pi_diamid_realm_peer = NULL;
|
||||
}
|
||||
if( shParseFlags(buffer, "ConnectPeer", "Ro_VOICE") )
|
||||
{
|
||||
//g_rovoice_conf_ext.pi_diamid_peer = strdup(g_sh_conf_ext.pi_diamid_peer);
|
||||
//g_rovoice_conf_ext.pi_diamid_realm_peer = strdup(g_sh_conf_ext.pi_diamid_realm_peer);
|
||||
//g_rovoice_conf_ext.peer_port = fd_g_config->ro_voiceport;
|
||||
AddRoLink(&g_sh_conf_ext, fd_g_config->ro_voiceport, 0);
|
||||
free(g_sh_conf_ext.pi_diamid_peer);
|
||||
g_sh_conf_ext.pi_diamid_peer = NULL;
|
||||
free(g_sh_conf_ext.pi_diamid_realm_peer);
|
||||
g_sh_conf_ext.pi_diamid_realm_peer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
shParseInt( buffer, "LogLevel", (uint16_t*)(&fd_g_debug_lvl) );
|
||||
|
||||
memset(buffer, 0, SH_PARSE_BUFFER_LEN);
|
||||
}
|
||||
|
||||
fclose (fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int shParse(struct fd_config * conf)
|
||||
{
|
||||
return shParse_(conf) || shParseExt(conf);
|
||||
}
|
||||
48
plat/diameter/extensions/sh_app/sh_conf.h
Normal file
48
plat/diameter/extensions/sh_app/sh_conf.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef __SH_CONF_H__
|
||||
#define __SH_CONF_H__
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include "sh_app.h"
|
||||
|
||||
typedef struct _SH_CONF_S
|
||||
{
|
||||
int mode;
|
||||
DiamId_t pi_diamid_peer;
|
||||
DiamId_t pi_diamid_realm_peer;
|
||||
uint16_t peer_port;
|
||||
}SH_CONF_S;
|
||||
|
||||
extern SH_CONF_S g_sh_conf_ext;
|
||||
|
||||
// Ro link from scp to ocs===============================
|
||||
typedef struct _Ro_Link_S
|
||||
{
|
||||
int bconn;
|
||||
SH_CONF_S cfg;
|
||||
}Ro_Link_S;
|
||||
|
||||
#define MaxRoLinkNum 4
|
||||
typedef struct _Ro_LinkSet
|
||||
{
|
||||
int smslknum;
|
||||
int voicelknum;
|
||||
int cursmslk;
|
||||
int curvoicelk;
|
||||
|
||||
Ro_Link_S smslk[MaxRoLinkNum];
|
||||
Ro_Link_S voicelk[MaxRoLinkNum];
|
||||
}Ro_LinkSet;
|
||||
extern Ro_LinkSet rolkset;
|
||||
//
|
||||
|
||||
//extern SH_CONF_S g_rosms_conf_ext;
|
||||
//extern SH_CONF_S g_rovoice_conf_ext;
|
||||
|
||||
int shParse(struct fd_config * conf);
|
||||
|
||||
|
||||
#endif /* __SH_CONF_H__ */
|
||||
4723
plat/diameter/extensions/sh_app/sh_dict.c
Normal file
4723
plat/diameter/extensions/sh_app/sh_dict.c
Normal file
File diff suppressed because it is too large
Load Diff
753
plat/diameter/extensions/sh_app/sh_serv.c
Normal file
753
plat/diameter/extensions/sh_app/sh_serv.c
Normal file
@@ -0,0 +1,753 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/* Install the dispatch callbacks */
|
||||
|
||||
#include "sh_app.h"
|
||||
|
||||
static struct disp_hdl * sh_hdl_fb = NULL; /* handler for fallback cb */
|
||||
static struct disp_hdl * sh_hdl_udr = NULL; /* handler for PUR req cb */
|
||||
static struct disp_hdl * sh_hdl_pur = NULL; /* handler for PUR req cb */
|
||||
|
||||
static struct sh_udr_msg g_udr_cmd;
|
||||
static struct sh_pur_msg g_pur_cmd;
|
||||
|
||||
|
||||
static struct sh_uda_msg g_uda_cmd;
|
||||
static struct sh_pua_msg g_pua_cmd;
|
||||
//static struct dict_avp_request __avp;
|
||||
|
||||
|
||||
|
||||
/* Default callback for the application. */
|
||||
#if 0
|
||||
static int ta_fb_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act)
|
||||
{
|
||||
/* This CB should never be called */
|
||||
TRACE_ENTRY("%p %p %p %p", msg, avp, sess, act);
|
||||
|
||||
fd_log_debug("Unexpected message received!");
|
||||
|
||||
return ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int sh_parse_pur(struct msg** msg)
|
||||
{
|
||||
struct msg* udr_msg = *msg;
|
||||
struct avp *avp, *grpavp=NULL;
|
||||
struct avp_hdr *avphdr;
|
||||
|
||||
LOG_D("fj sh_parse_pur");
|
||||
|
||||
SEARCH_AVP_("Session-Id", 0, &g_pur_cmd.pur_session_id);
|
||||
SEARCH_AVP_("DRMP", SH_VND_ID, &g_pur_cmd.pur_drmp);
|
||||
|
||||
SEARCH_AVP_("Vendor-Specific-Application-Id", 0, &g_pur_cmd.pur_vendor_specific_application_id);
|
||||
SEARCH_AVP_("Vendor-Id", 0, &g_pur_cmd.pur_vendor_id);
|
||||
SEARCH_AVP_("Auth-Application-Id", 0, &g_pur_cmd.pur_auth_application_d);
|
||||
SEARCH_AVP_("Acct-Application-Id", 0, &g_pur_cmd.pur_acct_application_id);
|
||||
|
||||
SEARCH_AVP_("Auth-Session-State", 0, &g_pur_cmd.pur_auth_session_state);
|
||||
SEARCH_AVP_("Origin-Host", 0, &g_pur_cmd.pur_origin_host);
|
||||
SEARCH_AVP_("Origin-Realm", 0, &g_pur_cmd.pur_origin_realm);
|
||||
SEARCH_AVP_("Destination-Host", 0, &g_pur_cmd.pur_destination_host);
|
||||
SEARCH_AVP_("Destination-Realm", 0, &g_pur_cmd.pur_destination_realm);
|
||||
|
||||
SEARCH_AVP_("Supported-Features", SH_VND_ID, &g_pur_cmd.pur_supported_features);
|
||||
SEARCH_AVP_("Feature-List-ID", SH_VND_ID, &g_pur_cmd.pur_feature_list_id);
|
||||
SEARCH_AVP_("Feature-List", SH_VND_ID, &g_pur_cmd.pur_feature_list);
|
||||
|
||||
|
||||
SEARCH_AVP_("User-Identity", SH_VND_ID, &g_pur_cmd.pur_user_identity);
|
||||
SEARCH_AVP_("Public-Identity", SH_VND_ID, &g_pur_cmd.pur_public_identity);
|
||||
SEARCH_AVP_("MSISDN", SH_VND_ID, &g_pur_cmd.pur_msisdn);
|
||||
|
||||
|
||||
SEARCH_AVP_("Wildcarded-Public-Identity", SH_VND_ID, &g_pur_cmd.pur_wildcarded_public_identity);
|
||||
SEARCH_AVP_("Wildcarded-IMPU", SH_VND_ID, &g_pur_cmd.pur_wildcarded_impu);
|
||||
SEARCH_AVP_("User-Name", 0, &g_pur_cmd.pur_user_name);
|
||||
SEARCH_AVP_("Data-Reference", SH_VND_ID, &g_pur_cmd.pur_data_reference);
|
||||
|
||||
SEARCH_AVP_("User-Data", SH_VND_ID, &g_pur_cmd.pur_user_date);
|
||||
|
||||
SEARCH_AVP_("OC-Supported-Features", SH_VND_ID, &g_pur_cmd.pur_oc_supported_features);
|
||||
SEARCH_AVP_("OC-Feature-Vector", SH_VND_ID, &g_pur_cmd.pur_oc_feature_vector);
|
||||
|
||||
/* Session-Id */
|
||||
PARSE_AVP_STR(udr_msg, g_pur_cmd.pur_session_id, avp, avphdr, "Session-Id", avphdr->avp_value->os.data)
|
||||
|
||||
/* DRMP */
|
||||
PARSE_AVP_U32(udr_msg, g_pur_cmd.pur_drmp, avp, avphdr, "DRMP", avphdr->avp_value->u32)
|
||||
|
||||
/* Vendor-Specific-Application-Id */
|
||||
CHECK_FCT( fd_msg_search_avp ( udr_msg, g_pur_cmd.pur_vendor_specific_application_id, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj Vendor-Specific-Application-Id");
|
||||
|
||||
/* Vendor-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pur_cmd.pur_vendor_id, avp, avphdr, "Vendor-Id", avphdr->avp_value->u32)
|
||||
|
||||
/* Auth-Application-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pur_cmd.pur_auth_application_d, avp, avphdr, "Auth-Application-Id", avphdr->avp_value->u32)
|
||||
|
||||
/* Acct-Application-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pur_cmd.pur_acct_application_id, avp, avphdr, "Acct-Application-Id", avphdr->avp_value->u32)
|
||||
}
|
||||
|
||||
/* Auth-Session-State */
|
||||
PARSE_AVP_U32(udr_msg, g_pur_cmd.pur_auth_session_state, avp, avphdr, "Auth-Session-State", avphdr->avp_value->i32)
|
||||
|
||||
/* Origin-Host */
|
||||
PARSE_AVP_STR(udr_msg, g_pur_cmd.pur_origin_host, avp, avphdr, "Origin-Host", avphdr->avp_value->os.data)
|
||||
|
||||
/* Origin-Realm */
|
||||
PARSE_AVP_STR(udr_msg, g_pur_cmd.pur_origin_realm, avp, avphdr, "Origin-Realm", avphdr->avp_value->os.data)
|
||||
|
||||
/* Destination-Host */
|
||||
PARSE_AVP_STR(udr_msg, g_pur_cmd.pur_destination_host, avp, avphdr, "Dest-Host", avphdr->avp_value->os.data)
|
||||
|
||||
/* Destination-Realm */
|
||||
PARSE_AVP_STR(udr_msg, g_pur_cmd.pur_destination_realm, avp, avphdr, "Dest-Realm", avphdr->avp_value->os.data)
|
||||
|
||||
/* Supported-Features */
|
||||
CHECK_FCT( fd_msg_search_avp ( udr_msg, g_pur_cmd.pur_supported_features, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj Supported-Features ");
|
||||
|
||||
/* Vendor-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pur_cmd.pur_vendor_id, avp, avphdr, "Vendor-Id", avphdr->avp_value->u32)
|
||||
|
||||
/* Feature-List-ID */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pur_cmd.pur_feature_list_id, avp, avphdr, "Feature-List-ID", avphdr->avp_value->u32)
|
||||
|
||||
/* Feature-List */
|
||||
PARSE_GRPAVP_U32(grpavp, g_pur_cmd.pur_feature_list, avp, avphdr, "Feature-List", avphdr->avp_value->u32)
|
||||
}
|
||||
|
||||
/* User-Identity */
|
||||
CHECK_FCT( fd_msg_search_avp ( udr_msg, g_pur_cmd.pur_user_identity, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj User-Identity");
|
||||
|
||||
/* Public-Identity */
|
||||
PARSE_GRPAVP_STR(grpavp, g_pur_cmd.pur_public_identity, avp, avphdr, "Public-Identity", avphdr->avp_value->os.data)
|
||||
|
||||
/* MSISDN */
|
||||
PARSE_GRPAVP_STR(grpavp, g_pur_cmd.pur_msisdn, avp, avphdr, "MSISDN", avphdr->avp_value->os.data)
|
||||
}
|
||||
|
||||
/* wildcarded_public_id */
|
||||
PARSE_AVP_STR(udr_msg, g_pur_cmd.pur_wildcarded_public_identity, avp, avphdr, "Wild-Pub-ID", avphdr->avp_value->os.data)
|
||||
|
||||
/* wildcarded_impu */
|
||||
PARSE_AVP_STR(udr_msg, g_pur_cmd.pur_wildcarded_impu, avp, avphdr, "Wild-Pub-IMPU", avphdr->avp_value->os.data)
|
||||
|
||||
/* User-Name */
|
||||
PARSE_AVP_STR(udr_msg, g_pur_cmd.pur_user_name, avp, avphdr, "User-Name", avphdr->avp_value->os.data)
|
||||
|
||||
/* User-Data */
|
||||
PARSE_AVP_STR(udr_msg, g_pur_cmd.pur_user_date, avp, avphdr, "User-Data", avphdr->avp_value->os.data)
|
||||
|
||||
|
||||
/* OC-Supported-Features */
|
||||
CHECK_FCT( fd_msg_search_avp ( udr_msg, g_pur_cmd.pur_oc_supported_features, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj OC-Supported-Features");
|
||||
|
||||
/* OC-Feature-Vector */
|
||||
PARSE_GRPAVP_U64(grpavp, g_pur_cmd.pur_oc_feature_vector, avp, avphdr, "OC-Feature-Vector", avphdr->avp_value->u64)
|
||||
}
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sh_parse_udr(struct msg** msg)
|
||||
{
|
||||
struct msg* udr_msg = *msg;
|
||||
struct avp *avp, *grpavp=NULL;
|
||||
struct avp_hdr *avphdr;
|
||||
|
||||
LOG_D("fj sh_parse_udr");
|
||||
|
||||
|
||||
SEARCH_AVP_("Session-Id", 0, &g_udr_cmd.udr_session_id);
|
||||
SEARCH_AVP_("DRMP", SH_VND_ID, &g_udr_cmd.udr_drmp);
|
||||
SEARCH_AVP_("Vendor-Specific-Application-Id", 0, &g_udr_cmd.udr_vendor_specific_application_id);
|
||||
SEARCH_AVP_("Vendor-Id", 0, &g_udr_cmd.udr_vendor_id);
|
||||
SEARCH_AVP_("Auth-Application-Id", 0, &g_udr_cmd.udr_auth_application_d);
|
||||
SEARCH_AVP_("Acct-Application-Id", 0, &g_udr_cmd.udr_acct_application_id);
|
||||
|
||||
SEARCH_AVP_("Auth-Session-State", 0, &g_udr_cmd.udr_auth_session_state);
|
||||
SEARCH_AVP_("Origin-Host", 0, &g_udr_cmd.udr_origin_host);
|
||||
SEARCH_AVP_("Origin-Realm", 0, &g_udr_cmd.udr_origin_realm);
|
||||
SEARCH_AVP_("Destination-Host", 0, &g_udr_cmd.udr_destination_host);
|
||||
SEARCH_AVP_("Destination-Realm", 0, &g_udr_cmd.udr_destination_realm);
|
||||
|
||||
SEARCH_AVP_("Supported-Features", SH_VND_ID, &g_udr_cmd.udr_supported_features);
|
||||
SEARCH_AVP_("Feature-List-ID", SH_VND_ID, &g_udr_cmd.udr_feature_list_id);
|
||||
SEARCH_AVP_("Feature-List", SH_VND_ID, &g_udr_cmd.udr_feature_list);
|
||||
|
||||
SEARCH_AVP_("User-Identity", SH_VND_ID, &g_udr_cmd.udr_user_identity);
|
||||
SEARCH_AVP_("Public-Identity", SH_VND_ID, &g_udr_cmd.udr_public_identity);
|
||||
SEARCH_AVP_("MSISDN", SH_VND_ID, &g_udr_cmd.udr_msisdn);
|
||||
|
||||
|
||||
SEARCH_AVP_("Wildcarded-Public-Identity", SH_VND_ID, &g_udr_cmd.udr_wildcarded_public_identity);
|
||||
SEARCH_AVP_("Wildcarded-IMPU", SH_VND_ID, &g_udr_cmd.udr_wildcarded_impu);
|
||||
SEARCH_AVP_("Server-Name", SH_VND_ID, &g_udr_cmd.udr_server_name);
|
||||
SEARCH_AVP_("Service-Indication", SH_VND_ID, &g_udr_cmd.udr_service_indication);
|
||||
SEARCH_AVP_("Data-Reference", SH_VND_ID, &g_udr_cmd.udr_data_reference);
|
||||
SEARCH_AVP_("Identity-Set", SH_VND_ID, &g_udr_cmd.udr_identity_set);
|
||||
SEARCH_AVP_("Requested-Domain", SH_VND_ID, &g_udr_cmd.udr_requested_domain);
|
||||
SEARCH_AVP_("Current-Location", SH_VND_ID, &g_udr_cmd.udr_current_location);
|
||||
SEARCH_AVP_("DSAI-Tag", SH_VND_ID, &g_udr_cmd.udr_dsai_tag);
|
||||
SEARCH_AVP_("Session-Priority", SH_VND_ID, &g_udr_cmd.udr_session_priority);
|
||||
SEARCH_AVP_("User-Name", 0, &g_udr_cmd.udr_user_name);
|
||||
SEARCH_AVP_("Requested-Nodes", SH_VND_ID, &g_udr_cmd.udr_requested_nodes);
|
||||
SEARCH_AVP_("Serving-Node-Indication", SH_VND_ID, &g_udr_cmd.udr_serving_node_indication);
|
||||
SEARCH_AVP_("Pre-paging-Supported", SH_VND_ID, &g_udr_cmd.udr_pre_paging_supported);
|
||||
SEARCH_AVP_("Local-Time-Zone-Indication", SH_VND_ID, &g_udr_cmd.udr_local_time_zone_indication);
|
||||
SEARCH_AVP_("UDR-Flags", SH_VND_ID, &g_udr_cmd.udr_udr_flags);
|
||||
|
||||
SEARCH_AVP_("Call-Reference-Info", SH_VND_ID, &g_udr_cmd.udr_call_reference_info);
|
||||
SEARCH_AVP_("Call-Reference-Number", SH_VND_ID, &g_udr_cmd.udr_call_reference_number);
|
||||
SEARCH_AVP_("AS-Number", SH_VND_ID, &g_udr_cmd.udr_as_number);
|
||||
|
||||
|
||||
SEARCH_AVP_("OC-Supported-Features", SH_VND_ID, &g_udr_cmd.udr_oc_supported_features);
|
||||
SEARCH_AVP_("OC-Feature-Vector", SH_VND_ID, &g_udr_cmd.udr_oc_feature_vector);
|
||||
|
||||
|
||||
/* Session-Id */
|
||||
PARSE_AVP_STR(udr_msg, g_udr_cmd.udr_session_id, avp, avphdr, "fj Session-Id", avphdr->avp_value->os.data)
|
||||
|
||||
/* DRMP */
|
||||
PARSE_AVP_U32(udr_msg, g_udr_cmd.udr_drmp, avp, avphdr, "fj DRMP", avphdr->avp_value->u32)
|
||||
|
||||
/* Vendor-Specific-Application-Id */
|
||||
CHECK_FCT( fd_msg_search_avp ( udr_msg, g_udr_cmd.udr_vendor_specific_application_id, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj Vendor-Specific-Application-Id");
|
||||
|
||||
/* Vendor-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_udr_cmd.udr_vendor_id, avp, avphdr, "Vendor-Id", avphdr->avp_value->u32)
|
||||
|
||||
/* Auth-Application-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_udr_cmd.udr_auth_application_d, avp, avphdr, "Auth-Application-Id", avphdr->avp_value->u32)
|
||||
|
||||
/* Acct-Application-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_udr_cmd.udr_acct_application_id, avp, avphdr, "Acct-Application-Id", avphdr->avp_value->u32)
|
||||
}
|
||||
|
||||
/* Auth-Session-State */
|
||||
PARSE_AVP_U32(udr_msg, g_udr_cmd.udr_auth_session_state, avp, avphdr, "Auth-Session-State", avphdr->avp_value->i32)
|
||||
|
||||
/* Origin-Host */
|
||||
PARSE_AVP_STR(udr_msg, g_udr_cmd.udr_origin_host, avp, avphdr, "Origin-Host", avphdr->avp_value->os.data)
|
||||
|
||||
/* Origin-Realm */
|
||||
PARSE_AVP_STR(udr_msg, g_udr_cmd.udr_origin_realm, avp, avphdr, "Origin-Realm", avphdr->avp_value->os.data)
|
||||
|
||||
/* Destination-Host */
|
||||
PARSE_AVP_STR(udr_msg, g_udr_cmd.udr_destination_host, avp, avphdr, "Dest-Host", avphdr->avp_value->os.data)
|
||||
|
||||
/* Destination-Realm */
|
||||
PARSE_AVP_STR(udr_msg, g_udr_cmd.udr_destination_realm, avp, avphdr, "Dest-Realm", avphdr->avp_value->os.data)
|
||||
|
||||
/* Supported-Features */
|
||||
CHECK_FCT( fd_msg_search_avp ( udr_msg, g_udr_cmd.udr_supported_features, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj Supported-Features ");
|
||||
|
||||
/* Vendor-Id */
|
||||
PARSE_GRPAVP_U32(grpavp, g_udr_cmd.udr_vendor_id, avp, avphdr, "Vendor-Id", avphdr->avp_value->u32)
|
||||
|
||||
/* Feature-List-ID */
|
||||
PARSE_GRPAVP_U32(grpavp, g_udr_cmd.udr_feature_list_id, avp, avphdr, "Feature-List-ID", avphdr->avp_value->u32)
|
||||
|
||||
/* Feature-List */
|
||||
PARSE_GRPAVP_U32(grpavp, g_udr_cmd.udr_feature_list, avp, avphdr, "Feature-List", avphdr->avp_value->u32)
|
||||
}
|
||||
|
||||
/* User-Identity */
|
||||
CHECK_FCT( fd_msg_search_avp ( udr_msg, g_udr_cmd.udr_user_identity, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj User-Identity");
|
||||
|
||||
/* Public-Identity */
|
||||
PARSE_GRPAVP_STR(grpavp, g_udr_cmd.udr_public_identity, avp, avphdr, "Public-Identity", avphdr->avp_value->os.data)
|
||||
|
||||
/* MSISDN */
|
||||
PARSE_GRPAVP_STR(grpavp, g_udr_cmd.udr_msisdn, avp, avphdr, "MSISDN", avphdr->avp_value->os.data)
|
||||
}
|
||||
|
||||
/* wildcarded_public_id */
|
||||
PARSE_AVP_STR(udr_msg, g_udr_cmd.udr_wildcarded_public_identity, avp, avphdr, "Wild-Pub-ID", avphdr->avp_value->os.data)
|
||||
|
||||
/* wildcarded_impu */
|
||||
PARSE_AVP_STR(udr_msg, g_udr_cmd.udr_wildcarded_impu, avp, avphdr, "Wild-Pub-IMPU", avphdr->avp_value->os.data)
|
||||
|
||||
/* server_name */
|
||||
PARSE_AVP_STR(udr_msg, g_udr_cmd.udr_server_name, avp, avphdr, "Server-Name", avphdr->avp_value->os.data)
|
||||
|
||||
/* Service-Indication */
|
||||
PARSE_AVP_STR(udr_msg, g_udr_cmd.udr_service_indication, avp, avphdr, "Service-ID", avphdr->avp_value->os.data)
|
||||
|
||||
/* Data-Reference */
|
||||
PARSE_AVP_U32(udr_msg, g_udr_cmd.udr_data_reference, avp, avphdr, "Data-Reference", avphdr->avp_value->u32)
|
||||
|
||||
/* Identity-Set */
|
||||
PARSE_AVP_U32(udr_msg, g_udr_cmd.udr_identity_set, avp, avphdr, "Identity-Set", avphdr->avp_value->u32)
|
||||
|
||||
/* Req-Domain*/
|
||||
PARSE_AVP_U32(udr_msg, g_udr_cmd.udr_requested_domain, avp, avphdr, "Req-Domain", avphdr->avp_value->u32)
|
||||
|
||||
/* Cur-Location*/
|
||||
PARSE_AVP_U32(udr_msg, g_udr_cmd.udr_current_location, avp, avphdr, "Cur-Location", avphdr->avp_value->u32)
|
||||
|
||||
/* DSAI-Tag */
|
||||
PARSE_AVP_STR(udr_msg, g_udr_cmd.udr_dsai_tag, avp, avphdr, "DSAI-Tag", avphdr->avp_value->os.data)
|
||||
|
||||
/* Session-Priority */
|
||||
PARSE_AVP_U32(udr_msg, g_udr_cmd.udr_session_priority, avp, avphdr, "Session-Priority", avphdr->avp_value->u32)
|
||||
|
||||
/* User-Name*/
|
||||
PARSE_AVP_STR(udr_msg, g_udr_cmd.udr_user_name, avp, avphdr, "User-Name", avphdr->avp_value->os.data)
|
||||
|
||||
PARSE_AVP_U32(udr_msg, g_udr_cmd.udr_requested_nodes, avp, avphdr, "Requested-Nodes", avphdr->avp_value->u32)
|
||||
PARSE_AVP_U32(udr_msg, g_udr_cmd.udr_serving_node_indication, avp, avphdr, "Serving-Node-Indication", avphdr->avp_value->u32)
|
||||
PARSE_AVP_U32(udr_msg, g_udr_cmd.udr_pre_paging_supported, avp, avphdr, "Pre-paging-Supported", avphdr->avp_value->u32)
|
||||
PARSE_AVP_U32(udr_msg, g_udr_cmd.udr_local_time_zone_indication, avp, avphdr, "Local-Time-Zone-Indication", avphdr->avp_value->u32)
|
||||
PARSE_AVP_U32(udr_msg, g_udr_cmd.udr_udr_flags, avp, avphdr, "UDR-Flags", avphdr->avp_value->u32)
|
||||
|
||||
/* Call-Reference-Info */
|
||||
CHECK_FCT( fd_msg_search_avp ( udr_msg, g_udr_cmd.udr_call_reference_info, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj Call-Reference-Info");
|
||||
|
||||
/* Call-Reference-Number */
|
||||
PARSE_GRPAVP_STR(grpavp, g_udr_cmd.udr_call_reference_number, avp, avphdr, "Call-Reference-Number", avphdr->avp_value->os.data)
|
||||
|
||||
/* AS-Number */
|
||||
PARSE_GRPAVP_STR(grpavp, g_udr_cmd.udr_as_number, avp, avphdr, "AS-Number", avphdr->avp_value->os.data)
|
||||
}
|
||||
|
||||
/* OC-Supported-Features */
|
||||
CHECK_FCT( fd_msg_search_avp ( udr_msg, g_udr_cmd.udr_oc_supported_features, &grpavp) );
|
||||
if(grpavp != NULL)
|
||||
{
|
||||
LOG_D("fj Call-Reference-Info");
|
||||
|
||||
/* OC-Feature-Vector */
|
||||
PARSE_GRPAVP_U64(grpavp, g_udr_cmd.udr_oc_feature_vector, avp, avphdr, "OC-Feature-Vector", avphdr->avp_value->u64)
|
||||
}
|
||||
out:
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sh_rec_pur( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act)
|
||||
{
|
||||
struct dict_object * pur_origin_host = NULL;
|
||||
|
||||
struct msg *ans/*, *qry*/;
|
||||
struct avp * a, *grpavp;
|
||||
union avp_value val;
|
||||
|
||||
TRACE_ENTRY("%p %p %p %p", msg, avp, sess, act);
|
||||
LOG_D("fj sh_rec_pur in\n");
|
||||
|
||||
if (msg == NULL)
|
||||
return EINVAL;
|
||||
|
||||
sh_parse_pur(msg);
|
||||
|
||||
SEARCH_AVP_("Origin-Host", 0, &pur_origin_host);
|
||||
|
||||
/* Value of Origin-Host */
|
||||
if (! (ta_conf->mode & MODE_BENCH)) {
|
||||
fprintf(stderr, "ECHO PUR received from ");
|
||||
CHECK_FCT( fd_msg_search_avp ( *msg, pur_origin_host, &a) );
|
||||
if (a) {
|
||||
struct avp_hdr * hdr;
|
||||
CHECK_FCT( fd_msg_avp_hdr( a, &hdr ) );
|
||||
fprintf(stderr, "'%.*s'", (int)hdr->avp_value->os.len, hdr->avp_value->os.data);
|
||||
} else {
|
||||
fprintf(stderr, "no_Origin-Host");
|
||||
}
|
||||
fprintf(stderr, ", replying...\n");
|
||||
}
|
||||
|
||||
/* Create answer header */
|
||||
// qry = *msg;
|
||||
CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, 0 ) );
|
||||
ans = *msg;
|
||||
|
||||
|
||||
/* set application id */
|
||||
{
|
||||
struct msg_hdr * msg_hdr = NULL;
|
||||
ASSERT( 0 == fd_msg_hdr ( ans, &msg_hdr ) );
|
||||
msg_hdr->msg_appl = SH_APP_ID;
|
||||
msg_hdr->msg_flags = msg_hdr->msg_flags & (~CMD_FLAG_PROXIABLE);
|
||||
}
|
||||
|
||||
|
||||
/* resolve uda avps */
|
||||
// SEARCH_AVP_("Session-Id", 0, &uda_session_id);
|
||||
SEARCH_AVP_("DRMP", SH_VND_ID, &g_pua_cmd.pua_drmp);
|
||||
SEARCH_AVP_("Vendor-Specific-Application-Id", 0, &g_pua_cmd.pua_vendor_specific_application_id);
|
||||
SEARCH_AVP_("Result-Code", 0, &g_pua_cmd.pua_result_code);
|
||||
SEARCH_AVP_("Experimental-Result", 0, &g_pua_cmd.pua_experimental_result);
|
||||
SEARCH_AVP_("Auth-Session-State", 0, &g_pua_cmd.pua_auth_session_state);
|
||||
SEARCH_AVP_("Origin-Host", 0, &g_pua_cmd.pua_origin_host);
|
||||
SEARCH_AVP_("Origin-Realm", 0, &g_pua_cmd.pua_origin_realm);
|
||||
|
||||
|
||||
SEARCH_AVP_("Wildcarded-Public-Identity", SH_VND_ID, &g_pua_cmd.pua_wildcarded_public_identity );
|
||||
SEARCH_AVP_("Wildcarded-IMPU", SH_VND_ID, &g_pua_cmd.pua_wildcarded_impu );
|
||||
SEARCH_AVP_("Repository-Data-ID", SH_VND_ID, &g_pua_cmd.pua_repository_data_id );
|
||||
|
||||
SEARCH_AVP_("Data-Reference", SH_VND_ID, &g_pua_cmd.pua_data_reference);
|
||||
|
||||
SEARCH_AVP_("Supported-Features", SH_VND_ID, &g_pua_cmd.pua_supported_features );
|
||||
SEARCH_AVP_("OC-Supported-Features", SH_VND_ID, &g_pua_cmd.pua_oc_supported_features );
|
||||
SEARCH_AVP_("OC-OLR", SH_VND_ID, &g_pua_cmd.pua_oc_olr );
|
||||
|
||||
|
||||
EN_AVP_U32(g_pua_cmd.pua_drmp, 0, ans, "DRMP Ok")
|
||||
|
||||
/* Set Vendor-Specific-Application-Id AVP if needed*/
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_new ( g_pua_cmd.pua_vendor_specific_application_id, 0, &grpavp ) );
|
||||
|
||||
EN_GRPAVP_U32("Vendor-Id", 0, g_pua_cmd.pua_vendor_id, SH_VND_ID)
|
||||
EN_GRPAVP_U32("Auth-Application-Id", 0, g_pua_cmd.pua_auth_application_d, SH_APP_ID)
|
||||
EN_GRPAVP_U32("Acct-Application-Id", 0,g_pua_cmd.pua_acct_application_id, SH_APP_ID)
|
||||
|
||||
CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, grpavp ) );
|
||||
|
||||
LOG_D("Vendor-Specific-Application-Id Ok\n");
|
||||
}
|
||||
|
||||
// EN_AVP_U32(g_uda_cmd.uda_result_code, 2001, ans, "Result-Code Ok\n")
|
||||
|
||||
/* Set the Experimental-Result group AVP if needed*/
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_new ( g_pua_cmd.pua_experimental_result, 0, &grpavp ) );
|
||||
|
||||
EN_GRPAVP_U32("Vendor-Id", 0, g_pua_cmd.pua_vendor_id, SH_VND_ID)
|
||||
EN_GRPAVP_U32("Experimental-Result-Code", 0, g_pua_cmd.pua_experimental_result_code, 3)
|
||||
CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, grpavp ) );
|
||||
|
||||
LOG_D("Experimental-Result Ok\n");
|
||||
}
|
||||
|
||||
EN_AVP_U32(g_pua_cmd.pua_auth_session_state, 0, ans, "Auth-Session-State Ok\n")
|
||||
|
||||
|
||||
EN_AVP_STR(g_pua_cmd.pua_wildcarded_public_identity, "wildcarded_public_id", ans, "wildcarded_public_id Ok")
|
||||
EN_AVP_STR( g_pua_cmd.pua_wildcarded_impu, "wildcarded_impu", ans, "wildcarded_impu Ok")
|
||||
/* Set the Repository-Data-ID AVP */
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_new ( g_pua_cmd.pua_repository_data_id, 0, &grpavp ) );
|
||||
|
||||
EN_GRPAVP_STR("Service-Indication", SH_VND_ID, g_pua_cmd.pua_service_indication, "Service-Indicatioin", grpavp)
|
||||
EN_GRPAVP_U32_("Sequence-Number", SH_VND_ID, g_pua_cmd.pua_sequence_number, 1234, grpavp)
|
||||
|
||||
CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, grpavp ) );
|
||||
|
||||
LOG_D("Repository-Data-ID Ok\n");
|
||||
}
|
||||
|
||||
EN_AVP_U32(g_pua_cmd.pua_data_reference, 0, ans, "Data-Reference Ok\n")
|
||||
|
||||
/* Set the Supported-Features group AVP if needed*/
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_new ( g_pua_cmd.pua_supported_features, 0, &grpavp ) );
|
||||
|
||||
EN_GRPAVP_U32_("Vendor-Id", 0, g_pua_cmd.pua_vendor_id, SH_VND_ID, grpavp)
|
||||
EN_GRPAVP_U32_("Feature-List-ID", SH_VND_ID, g_pua_cmd.pua_feature_list_id, 2, grpavp)
|
||||
EN_GRPAVP_U32_("Feature-List", SH_VND_ID, g_pua_cmd.pua_feature_list, 3, grpavp)
|
||||
|
||||
CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, grpavp ) );
|
||||
|
||||
LOG_D("Supported-Features Ok\n");
|
||||
}
|
||||
|
||||
/* Set the OC-Supported-Features AVP */
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_new ( g_pua_cmd.pua_oc_supported_features, 0, &grpavp ) );
|
||||
|
||||
EN_GRPAVP_U64("OC-Feature-Vector", SH_VND_ID, g_pua_cmd.pua_oc_feature_vector, 1)
|
||||
|
||||
CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, grpavp ) );
|
||||
|
||||
LOG_D("OC-Feature-Vector Ok\n");
|
||||
}
|
||||
|
||||
/* Set the OC-OLR group AVP if needed*/
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_new ( g_pua_cmd.pua_oc_olr, 0, &grpavp ) );
|
||||
|
||||
EN_GRPAVP_U64("OC-Sequence-Number", SH_VND_ID, g_pua_cmd.pua_oc_sequence_number, 1)
|
||||
EN_GRPAVP_U32("OC-Report-Type", SH_VND_ID,g_pua_cmd.pua_oc_report_type, 2)
|
||||
EN_GRPAVP_U32("OC-Reduction-Percentage", SH_VND_ID, g_pua_cmd.pua_oc_reduction_percentage, 3)
|
||||
EN_GRPAVP_U32("OC-Validity-Duration", SH_VND_ID, g_pua_cmd.pua_oc_validity_duration, 4)
|
||||
|
||||
CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, grpavp ) );
|
||||
|
||||
LOG_D("OC-OLR Ok\n");
|
||||
}
|
||||
|
||||
/* Set the Origin-Host, Origin-Realm, Result-Code AVPs */
|
||||
CHECK_FCT( fd_msg_rescode_set( ans, "DIAMETER_SUCCESS", NULL, NULL, 1 ) );
|
||||
|
||||
/* Send the answer */
|
||||
CHECK_FCT( fd_msg_send( msg, NULL, NULL ) );
|
||||
|
||||
/* Add this value to the stats */
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), );
|
||||
ta_conf->stats.nb_echoed++;
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), );
|
||||
|
||||
out:
|
||||
printf("sh_rec_pur end.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sh_rec_udr( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act)
|
||||
{
|
||||
struct msg *ans/*, *qry*/;
|
||||
struct avp * a, *grpavp;
|
||||
union avp_value val;
|
||||
|
||||
TRACE_ENTRY("%p %p %p %p", msg, avp, sess, act);
|
||||
LOG_D("fj sh_rec_udr in\n");
|
||||
|
||||
if (msg == NULL)
|
||||
return EINVAL;
|
||||
|
||||
sh_parse_udr(msg);
|
||||
|
||||
SEARCH_AVP_("Origin-Host", 0, &g_uda_cmd.uda_origin_host);
|
||||
SEARCH_AVP_("Session-Id", 0, &g_uda_cmd.uda_session_id);
|
||||
|
||||
/* Value of Origin-Host */
|
||||
if (! (ta_conf->mode & MODE_BENCH)) {
|
||||
fprintf(stderr, "ECHO UDR received from ");
|
||||
CHECK_FCT( fd_msg_search_avp ( *msg, g_uda_cmd.uda_origin_host, &a) );
|
||||
if (a) {
|
||||
struct avp_hdr * hdr;
|
||||
CHECK_FCT( fd_msg_avp_hdr( a, &hdr ) );
|
||||
fprintf(stderr, "'%.*s'", (int)hdr->avp_value->os.len, hdr->avp_value->os.data);
|
||||
} else {
|
||||
fprintf(stderr, "no_Origin-Host");
|
||||
}
|
||||
fprintf(stderr, ", replying...\n");
|
||||
}
|
||||
|
||||
/* Create answer header */
|
||||
// qry = *msg;
|
||||
CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, 0 ) );
|
||||
ans = *msg;
|
||||
|
||||
/* set application id */
|
||||
{
|
||||
struct msg_hdr * msg_hdr = NULL;
|
||||
ASSERT( 0 == fd_msg_hdr ( ans, &msg_hdr ) );
|
||||
msg_hdr->msg_appl = SH_APP_ID;
|
||||
msg_hdr->msg_flags = msg_hdr->msg_flags & (~CMD_FLAG_PROXIABLE);
|
||||
}
|
||||
|
||||
/* resolve uda avps */
|
||||
// SEARCH_AVP_("Session-Id", 0, &uda_session_id);
|
||||
SEARCH_AVP_("DRMP", SH_VND_ID, &g_uda_cmd.uda_drmp);
|
||||
SEARCH_AVP_("Vendor-Specific-Application-Id", 0, &g_uda_cmd.uda_vendor_specific_application_id);
|
||||
SEARCH_AVP_("Result-Code", 0, &g_uda_cmd.uda_result_code);
|
||||
SEARCH_AVP_("Experimental-Result", 0, &g_uda_cmd.uda_experimental_result);
|
||||
SEARCH_AVP_("Auth-Session-State", 0, &g_uda_cmd.uda_auth_session_state);
|
||||
|
||||
SEARCH_AVP_("Origin-Realm", 0, &g_uda_cmd.uda_origin_realm);
|
||||
|
||||
SEARCH_AVP_("Supported-Features", SH_VND_ID, &g_uda_cmd.uda_supported_features );
|
||||
SEARCH_AVP_("Wildcarded-Public-Identity", SH_VND_ID, &g_uda_cmd.uda_wildcarded_public_identity );
|
||||
SEARCH_AVP_("Wildcarded-IMPU", SH_VND_ID, &g_uda_cmd.uda_wildcarded_impu );
|
||||
SEARCH_AVP_("User-Data", SH_VND_ID, &g_uda_cmd.uda_user_data );
|
||||
SEARCH_AVP_("OC-Supported-Features", SH_VND_ID, &g_uda_cmd.uda_oc_supported_features );
|
||||
SEARCH_AVP_("OC-OLR", SH_VND_ID, &g_uda_cmd.uda_oc_olr );
|
||||
|
||||
|
||||
EN_AVP_U32(g_uda_cmd.uda_drmp, 0, ans, "DRMP Ok")
|
||||
|
||||
/* Set Vendor-Specific-Application-Id AVP if needed*/
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_new ( g_uda_cmd.uda_vendor_specific_application_id, 0, &grpavp ) );
|
||||
|
||||
EN_GRPAVP_U32("Vendor-Id", 0, g_uda_cmd.uda_vendor_id, SH_VND_ID)
|
||||
EN_GRPAVP_U32("Auth-Application-Id", 0, g_uda_cmd.uda_auth_application_d, SH_APP_ID)
|
||||
EN_GRPAVP_U32("Acct-Application-Id", 0,g_uda_cmd.uda_acct_application_id, SH_APP_ID)
|
||||
|
||||
CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, grpavp ) );
|
||||
|
||||
LOG_D("Vendor-Specific-Application-Id Ok\n");
|
||||
}
|
||||
|
||||
// EN_AVP_U32(g_uda_cmd.uda_result_code, 2001, ans, "Result-Code Ok\n")
|
||||
|
||||
/* Set the Experimental-Result group AVP if needed*/
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_new ( g_uda_cmd.uda_experimental_result, 0, &grpavp ) );
|
||||
|
||||
EN_GRPAVP_U32("Vendor-Id", 0, g_uda_cmd.uda_vendor_id, 3)
|
||||
EN_GRPAVP_U32("Experimental-Result-Code", 0, g_uda_cmd.uda_experimental_result_code, 3)
|
||||
CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, grpavp ) );
|
||||
|
||||
LOG_D("Experimental-Result Ok\n");
|
||||
}
|
||||
|
||||
EN_AVP_U32(g_uda_cmd.uda_auth_session_state, 0, ans, "Auth-Session-State Ok\n")
|
||||
|
||||
/* Set the Supported-Features group AVP if needed*/
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_new ( g_uda_cmd.uda_supported_features, 0, &grpavp ) );
|
||||
|
||||
EN_GRPAVP_U32("Vendor-Id", 0, g_uda_cmd.uda_vendor_id, 1)
|
||||
EN_GRPAVP_U32("Feature-List-ID", SH_VND_ID, g_uda_cmd.uda_feature_list_id, 2)
|
||||
EN_GRPAVP_U32("Feature-List", SH_VND_ID, g_uda_cmd.uda_feature_list, 3)
|
||||
|
||||
CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, grpavp ) );
|
||||
|
||||
LOG_D("Supported-Features Ok\n");
|
||||
}
|
||||
EN_AVP_STR(g_uda_cmd.uda_wildcarded_public_identity, "wildcarded_public_id", ans, "wildcarded_public_id Ok")
|
||||
EN_AVP_STR( g_uda_cmd.uda_wildcarded_impu, "wildcarded_impu", ans, "wildcarded_impu Ok")
|
||||
EN_AVP_STR( g_uda_cmd.uda_user_data, "User-Data", ans, "User-Data Ok")
|
||||
/* Set the OC-Supported-Features AVP */
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_new ( g_uda_cmd.uda_oc_supported_features, 0, &grpavp ) );
|
||||
|
||||
EN_GRPAVP_U64("OC-Feature-Vector", SH_VND_ID, g_uda_cmd.uda_oc_feature_vector, 1)
|
||||
|
||||
CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, grpavp ) );
|
||||
|
||||
LOG_D("OC-Feature-Vector Ok\n");
|
||||
}
|
||||
/* Set the OC-OLR group AVP if needed*/
|
||||
{
|
||||
CHECK_FCT( fd_msg_avp_new ( g_uda_cmd.uda_oc_olr, 0, &grpavp ) );
|
||||
|
||||
EN_GRPAVP_U64("OC-Sequence-Number", SH_VND_ID, g_uda_cmd.uda_oc_sequence_number, 1)
|
||||
EN_GRPAVP_U32("OC-Report-Type", SH_VND_ID,g_uda_cmd.uda_oc_report_type, 2)
|
||||
EN_GRPAVP_U32("OC-Reduction-Percentage", SH_VND_ID, g_uda_cmd.uda_oc_reduction_percentage, 3)
|
||||
EN_GRPAVP_U32("OC-Validity-Duration", SH_VND_ID, g_uda_cmd.uda_oc_validity_duration, 4)
|
||||
|
||||
CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, grpavp ) );
|
||||
|
||||
LOG_D("Supported-Features Ok\n");
|
||||
#if SH_TEST_ON
|
||||
fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, ans, fd_g_config->cnf_dict, 0, 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set the Origin-Host, Origin-Realm, Result-Code AVPs */
|
||||
CHECK_FCT( fd_msg_rescode_set( ans, "DIAMETER_SUCCESS", NULL, NULL, 1 ) );
|
||||
|
||||
/* Send the answer */
|
||||
CHECK_FCT( fd_msg_send( msg, NULL, NULL ) );
|
||||
|
||||
/* Add this value to the stats */
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), );
|
||||
ta_conf->stats.nb_echoed++;
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), );
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern struct dict_object * sh_appli;
|
||||
extern struct dict_object * sh_vendor;
|
||||
extern struct dict_object * udr_cmd;
|
||||
extern struct dict_object * pur_cmd;
|
||||
|
||||
int sh_serv_init(void)
|
||||
{
|
||||
struct disp_when data;
|
||||
|
||||
TRACE_DEBUG(FULL, "Initializing dispatch callbacks for test");
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.app = sh_appli;
|
||||
data.command = udr_cmd; // udr_cmd; // ta_cmd_r;
|
||||
|
||||
/* fallback CB if command != Test-Request received */
|
||||
// CHECK_FCT( fd_disp_register( ta_fb_cb, DISP_HOW_APPID, &data, NULL, &sh_hdl_fb ) );
|
||||
|
||||
/* Now specific handler for UDR */
|
||||
CHECK_FCT( fd_disp_register( sh_rec_udr, DISP_HOW_CC, &data, NULL, &sh_hdl_udr ) );
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.app = sh_appli;
|
||||
data.command = pur_cmd; // udr_cmd; // ta_cmd_r;
|
||||
/* Now specific handler for PUR */
|
||||
CHECK_FCT( fd_disp_register( sh_rec_pur, DISP_HOW_CC, &data, NULL, &sh_hdl_pur ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sh_serv_fini(void)
|
||||
{
|
||||
if (sh_hdl_fb) {
|
||||
(void) fd_disp_unregister(&sh_hdl_fb, NULL);
|
||||
}
|
||||
if (sh_hdl_udr) {
|
||||
(void) fd_disp_unregister(&sh_hdl_udr, NULL);
|
||||
}
|
||||
if (sh_hdl_pur) {
|
||||
(void) fd_disp_unregister(&sh_hdl_pur, NULL);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
177
plat/diameter/extensions/sh_app/ta_conf.l
Normal file
177
plat/diameter/extensions/sh_app/ta_conf.l
Normal file
@@ -0,0 +1,177 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/* Lex extension's configuration parser.
|
||||
*
|
||||
* The configuration file contains a default priority, and a list of peers with optional overwite priority.
|
||||
* -- see the app_test.conf.sample file for more detail.
|
||||
*/
|
||||
|
||||
%{
|
||||
#include "test_app.h"
|
||||
/* Include yacc tokens definitions */
|
||||
#include "ta_conf.tab.h"
|
||||
|
||||
/* Update the column information */
|
||||
#define YY_USER_ACTION { \
|
||||
yylloc->first_column = yylloc->last_column + 1; \
|
||||
yylloc->last_column = yylloc->first_column + yyleng - 1; \
|
||||
}
|
||||
|
||||
/* Avoid warning with newer flex */
|
||||
#define YY_NO_INPUT
|
||||
|
||||
%}
|
||||
|
||||
%option bison-bridge bison-locations
|
||||
%option noyywrap
|
||||
%option nounput
|
||||
|
||||
%%
|
||||
|
||||
/* Update the line count */
|
||||
\n {
|
||||
yylloc->first_line++;
|
||||
yylloc->last_line++;
|
||||
yylloc->last_column=0;
|
||||
}
|
||||
|
||||
/* Eat all spaces but not new lines */
|
||||
([[:space:]]{-}[\n])+ ;
|
||||
/* Eat all comments */
|
||||
#.*$ ;
|
||||
|
||||
/* Recognize any integer */
|
||||
[-]?[[:digit:]]+ {
|
||||
/* Convert this to an integer value */
|
||||
int ret=0;
|
||||
ret = sscanf(yytext, "%i", &yylval->integer);
|
||||
if (ret != 1) {
|
||||
/* No matching: an error occurred */
|
||||
fd_log_debug("Unable to convert the value '%s' to a valid number: %s", yytext, strerror(errno));
|
||||
return LEX_ERROR; /* trig an error in yacc parser */
|
||||
/* Maybe we could REJECT instead of failing here? */
|
||||
}
|
||||
return INTEGER;
|
||||
}
|
||||
|
||||
/* Recognize quoted strings -- we do not support escaped \" in the string currently. */
|
||||
\"[^\"]+\" {
|
||||
/* Match a quoted string. Let's be very permissive. */
|
||||
yylval->string = strdup(yytext+1);
|
||||
if (!yylval->string) {
|
||||
fd_log_debug("Unable to copy the string '%s': %s", yytext, strerror(errno));
|
||||
TRACE_DEBUG(INFO, "strdup failed");
|
||||
return LEX_ERROR; /* trig an error in yacc parser */
|
||||
}
|
||||
yylval->string[strlen(yytext) - 2] = '\0';
|
||||
return QSTRING;
|
||||
}
|
||||
|
||||
/* Recognize the tokens */
|
||||
(?i:"vendor-id") {
|
||||
return VENDOR_ID;
|
||||
}
|
||||
|
||||
(?i:"appli-id") {
|
||||
return APPLI_ID;
|
||||
}
|
||||
|
||||
(?i:"cmd-id") {
|
||||
return CMD_ID;
|
||||
}
|
||||
|
||||
(?i:"avp-id") {
|
||||
return AVP_ID;
|
||||
}
|
||||
|
||||
(?i:"long-avp-id") {
|
||||
return LONG_AVP_ID;
|
||||
}
|
||||
|
||||
(?i:"long-avp-len") {
|
||||
return LONG_AVP_LEN;
|
||||
}
|
||||
|
||||
(?i:"mode") {
|
||||
return MODE;
|
||||
}
|
||||
|
||||
(?i:"server") {
|
||||
yylval->integer = MODE_SERV;
|
||||
return INTEGER;
|
||||
}
|
||||
|
||||
(?i:"client") {
|
||||
yylval->integer = MODE_CLI;
|
||||
return INTEGER;
|
||||
}
|
||||
|
||||
(?i:"both") {
|
||||
yylval->integer = MODE_SERV | MODE_CLI;
|
||||
return INTEGER;
|
||||
}
|
||||
|
||||
(?i:"dest-realm") {
|
||||
return DEST_REALM;
|
||||
}
|
||||
|
||||
(?i:"dest-host") {
|
||||
return DEST_HOST;
|
||||
}
|
||||
|
||||
(?i:"user-name") {
|
||||
return USER_NAME;
|
||||
}
|
||||
|
||||
(?i:"Signal") {
|
||||
return SIGNAL;
|
||||
}
|
||||
|
||||
(?i:"Benchmark") {
|
||||
return BENCH;
|
||||
}
|
||||
|
||||
|
||||
/* Valid single characters for yyparse */
|
||||
[=;] { return yytext[0]; }
|
||||
|
||||
/* Unrecognized sequence, if it did not match any previous pattern */
|
||||
[^[:space:]"*=>;\n]+ {
|
||||
fd_log_debug("Unrecognized text on line %d col %d: '%s'.", yylloc->first_line, yylloc->first_column, yytext);
|
||||
return LEX_ERROR;
|
||||
}
|
||||
|
||||
%%
|
||||
239
plat/diameter/extensions/sh_app/ta_conf.y
Normal file
239
plat/diameter/extensions/sh_app/ta_conf.y
Normal file
@@ -0,0 +1,239 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/* Yacc extension's configuration parser.
|
||||
* See doc/app_test.conf.sample for configuration file format
|
||||
*/
|
||||
|
||||
/* For development only : */
|
||||
%debug
|
||||
%error-verbose
|
||||
|
||||
/* The parser receives the configuration file filename as parameter */
|
||||
%parse-param {char * conffile}
|
||||
|
||||
/* Keep track of location */
|
||||
%locations
|
||||
%pure-parser
|
||||
|
||||
%{
|
||||
#include "test_app.h"
|
||||
#include "ta_conf.tab.h" /* bison is not smart enough to define the YYLTYPE before including this code, so... */
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* Forward declaration */
|
||||
int yyparse(char * conffile);
|
||||
|
||||
/* Parse the configuration file */
|
||||
int ta_conf_handle(char * conffile)
|
||||
{
|
||||
extern FILE * ta_confin;
|
||||
int ret;
|
||||
|
||||
TRACE_ENTRY("%p", conffile);
|
||||
|
||||
TRACE_DEBUG (FULL, "Parsing configuration file: %s...", conffile);
|
||||
|
||||
ta_confin = fopen(conffile, "r");
|
||||
if (ta_confin == NULL) {
|
||||
ret = errno;
|
||||
fd_log_debug("Unable to open extension configuration file %s for reading: %s", conffile, strerror(ret));
|
||||
TRACE_DEBUG (INFO, "Error occurred, message logged -- configuration file.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = yyparse(conffile);
|
||||
|
||||
fclose(ta_confin);
|
||||
|
||||
if (ret != 0) {
|
||||
TRACE_DEBUG (INFO, "Unable to parse the configuration file.");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The Lex parser prototype */
|
||||
int ta_conflex(YYSTYPE *lvalp, YYLTYPE *llocp);
|
||||
|
||||
/* Function to report the errors */
|
||||
void yyerror (YYLTYPE *ploc, char * conffile, char const *s)
|
||||
{
|
||||
TRACE_DEBUG(INFO, "Error in configuration parsing");
|
||||
|
||||
if (ploc->first_line != ploc->last_line)
|
||||
fd_log_debug("%s:%d.%d-%d.%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s);
|
||||
else if (ploc->first_column != ploc->last_column)
|
||||
fd_log_debug("%s:%d.%d-%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_column, s);
|
||||
else
|
||||
fd_log_debug("%s:%d.%d : %s", conffile, 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
|
||||
|
||||
/* Key words */
|
||||
%token VENDOR_ID
|
||||
%token APPLI_ID
|
||||
%token CMD_ID
|
||||
%token AVP_ID
|
||||
%token LONG_AVP_ID
|
||||
%token LONG_AVP_LEN
|
||||
%token MODE
|
||||
%token DEST_REALM
|
||||
%token DEST_HOST
|
||||
%token USER_NAME
|
||||
%token SIGNAL
|
||||
%token BENCH
|
||||
|
||||
/* Tokens and types for routing table definition */
|
||||
/* A (de)quoted string (malloc'd in lex parser; it must be freed after use) */
|
||||
%token <string> QSTRING
|
||||
|
||||
/* An integer value */
|
||||
%token <integer> INTEGER
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------- */
|
||||
%%
|
||||
|
||||
/* The grammar definition */
|
||||
conffile: /* empty grammar is OK */
|
||||
| conffile vendor
|
||||
| conffile appli
|
||||
| conffile cmd
|
||||
| conffile avp
|
||||
| conffile long_avp_id
|
||||
| conffile long_avp_len
|
||||
| conffile mode
|
||||
| conffile dstrealm
|
||||
| conffile dsthost
|
||||
| conffile usrname
|
||||
| conffile signal
|
||||
| conffile bench
|
||||
;
|
||||
|
||||
vendor: VENDOR_ID '=' INTEGER ';'
|
||||
{
|
||||
ta_conf->vendor_id = $3;
|
||||
}
|
||||
;
|
||||
|
||||
appli: APPLI_ID '=' INTEGER ';'
|
||||
{
|
||||
ta_conf->appli_id = $3;
|
||||
}
|
||||
;
|
||||
|
||||
cmd: CMD_ID '=' INTEGER ';'
|
||||
{
|
||||
ta_conf->cmd_id = $3;
|
||||
}
|
||||
;
|
||||
|
||||
avp: AVP_ID '=' INTEGER ';'
|
||||
{
|
||||
ta_conf->avp_id = $3;
|
||||
}
|
||||
;
|
||||
|
||||
long_avp_id: LONG_AVP_ID '=' INTEGER ';'
|
||||
{
|
||||
ta_conf->long_avp_id = $3;
|
||||
}
|
||||
;
|
||||
|
||||
long_avp_len: LONG_AVP_LEN '=' INTEGER ';'
|
||||
{
|
||||
ta_conf->long_avp_len = $3;
|
||||
}
|
||||
;
|
||||
|
||||
mode: MODE '=' INTEGER ';'
|
||||
{
|
||||
ta_conf->mode = $3 | (ta_conf->mode & ~3); /* overwrite the 2 lsb */
|
||||
}
|
||||
;
|
||||
|
||||
bench: BENCH ';'
|
||||
{
|
||||
ta_conf->mode |= MODE_BENCH;
|
||||
}
|
||||
| BENCH INTEGER INTEGER ';'
|
||||
{
|
||||
ta_conf->mode |= MODE_BENCH;
|
||||
ta_conf->bench_duration = $2;
|
||||
ta_conf->bench_concur = $3;
|
||||
}
|
||||
;
|
||||
|
||||
dstrealm: DEST_REALM '=' QSTRING ';'
|
||||
{
|
||||
free(ta_conf->dest_realm);
|
||||
ta_conf->dest_realm = $3;
|
||||
}
|
||||
;
|
||||
|
||||
dsthost: DEST_HOST '=' QSTRING ';'
|
||||
{
|
||||
free(ta_conf->dest_host);
|
||||
ta_conf->dest_host = $3;
|
||||
}
|
||||
;
|
||||
|
||||
usrname: USER_NAME '=' QSTRING ';'
|
||||
{
|
||||
free(ta_conf->user_name);
|
||||
ta_conf->user_name = $3;
|
||||
}
|
||||
;
|
||||
|
||||
signal: SIGNAL '=' INTEGER ';'
|
||||
{
|
||||
ta_conf->signal = $3;
|
||||
}
|
||||
;
|
||||
26
plat/diameter/freeDiameter-1.conf
Normal file
26
plat/diameter/freeDiameter-1.conf
Normal file
@@ -0,0 +1,26 @@
|
||||
#Service mode 1:Server 2:Client 4:Server&Client
|
||||
ServiceMod = 3;
|
||||
|
||||
Identity = "a.client.com";
|
||||
|
||||
Realm = "client.com";
|
||||
|
||||
Port = 3868;
|
||||
|
||||
SecPort = 0;
|
||||
|
||||
SCTPStr = 10;
|
||||
|
||||
#TLS_Cred = "./cacert.pem",
|
||||
# "./cakey.pem";
|
||||
#TLS_CA = "./cacert.pem";
|
||||
|
||||
#Connect to peer. e.g ConnectPeer = "peer1.localdomain" { No_TLS; No_FWD; No_IP4; No_IP6; No_TCP; No_SCTP; Prefer_TCP; };
|
||||
#SCTP
|
||||
#ConnectPeer = "a.server.net" { Realm = "server.net"; No_TLS; No_FWD; No_TCP; };
|
||||
#TCP
|
||||
ConnectPeer = "a.server.net" { Realm = "server.net"; No_TLS; No_FWD; No_SCTP; Prefer_TCP; };
|
||||
|
||||
#Log levels 0:anything 1:debug 3:notice 5:error 6:fatal
|
||||
LogLevel = 3;
|
||||
|
||||
25
plat/diameter/freeDiameter-2.conf
Normal file
25
plat/diameter/freeDiameter-2.conf
Normal file
@@ -0,0 +1,25 @@
|
||||
#Service mode 1:Server 2:Client 3:Server&Client
|
||||
ServiceMod = 3;
|
||||
|
||||
Identity = "a.server.net";
|
||||
|
||||
Realm = "server.net";
|
||||
|
||||
Port = 3868;
|
||||
|
||||
SecPort = 0;
|
||||
|
||||
SCTPStr = 10;
|
||||
|
||||
#TLS_Cred = "./cacert.pem",
|
||||
# "./cakey.pem";
|
||||
#TLS_CA = "./cacert.pem";
|
||||
|
||||
#Connect to peer. e.g ConnectPeer = "peer1.localdomain" { No_TLS; No_FWD; No_IP4; No_IP6; No_TCP; No_SCTP; Prefer_TCP; };
|
||||
#SCTP
|
||||
#ConnectPeer = "a.client.com" { Realm = "client.com"; No_TLS; No_FWD; No_TCP; };
|
||||
#TCP
|
||||
ConnectPeer = "a.client.com" { Realm = "client.com"; No_FWD; No_TLS; No_SCTP; Prefer_TCP; };
|
||||
|
||||
#Log levels 0:anything 1:debug 3:notice 5:error 6:fatal
|
||||
LogLevel = 3;
|
||||
108
plat/diameter/freeDiameterd/freeDiameter-host.h
Normal file
108
plat/diameter/freeDiameterd/freeDiameter-host.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/* Configuration from compile-time */
|
||||
#ifndef FD_IS_CONFIG
|
||||
#define FD_IS_CONFIG
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* #undef HAVE_NTOHLL */
|
||||
#define HAVE_MALLOC_H
|
||||
/* #undef HAVE_SIGNALENT_H */
|
||||
#define HAVE_AI_ADDRCONFIG
|
||||
#define HAVE_CLOCK_GETTIME
|
||||
#define HAVE_STRNDUP
|
||||
#define HAVE_PTHREAD_BAR
|
||||
|
||||
/* #undef HOST_BIG_ENDIAN */
|
||||
|
||||
/* #undef DISABLE_SCTP */
|
||||
/* #undef DEBUG_SCTP */
|
||||
/* #undef DEBUG_WITH_META */
|
||||
/* #undef SCTP_USE_MAPPED_ADDRESSES */
|
||||
#define SCTP_CONNECTX_4_ARGS
|
||||
/* #undef SKIP_DLCLOSE */
|
||||
/* #undef DIAMID_IDNA_IGNORE */
|
||||
/* #undef DIAMID_IDNA_REJECT */
|
||||
/* #undef DISABLE_PEER_EXPIRY */
|
||||
/* #undef WORKAROUND_ACCEPT_INVALID_VSAI */
|
||||
#define GNUTLS_VERSION_210
|
||||
#define GNUTLS_VERSION_212
|
||||
/* #undef GNUTLS_VERSION_300 */
|
||||
/* #undef GNUTLS_VERSION_310 */
|
||||
|
||||
/* #undef ERRORS_ON_TODO */
|
||||
/* #undef DEBUG */
|
||||
|
||||
#define FD_PROJECT_BINARY "agtocs"
|
||||
//#define FD_PROJECT_NAME "freeDiameter"
|
||||
#define FD_PROJECT_NAME "AGT_OCS"
|
||||
|
||||
#define FD_PROJECT_VERSION_MAJOR 1
|
||||
#ifndef FD_PROJECT_VERSION_MAJOR
|
||||
# define FD_PROJECT_VERSION_MAJOR 0
|
||||
#endif /*FD_PROJECT_VERSION_MAJOR*/
|
||||
#define FD_PROJECT_VERSION_MINOR 2
|
||||
#ifndef FD_PROJECT_VERSION_MINOR
|
||||
# define FD_PROJECT_VERSION_MINOR 0
|
||||
#endif /*FD_PROJECT_VERSION_MINOR*/
|
||||
#define FD_PROJECT_VERSION_REV 1
|
||||
#ifndef FD_PROJECT_VERSION_REV
|
||||
# define FD_PROJECT_VERSION_REV 0
|
||||
#endif /*FD_PROJECT_VERSION_REV*/
|
||||
#define FD_PROJECT_VERSION_API 6
|
||||
#ifndef FD_PROJECT_VERSION_API
|
||||
# define FD_PROJECT_VERSION_API 0
|
||||
#endif /*FD_PROJECT_VERSION_API*/
|
||||
#define FD_PROJECT_COPYRIGHT "Copyright (c) 2008-2015, WIDE Project (www.wide.ad.jp) and NICT (www.nict.go.jp)"
|
||||
|
||||
#define DEFAULT_CONF_PATH "DEFAULT_CONF_PATH"
|
||||
#define DEFAULT_EXTENSIONS_PATH "CMAKE_INSTALL_PREFIX/INSTALL_EXTENSIONS_SUFFIX"
|
||||
|
||||
#ifndef FD_DEFAULT_CONF_FILENAME
|
||||
#define FD_DEFAULT_CONF_FILENAME "freeDiameter.conf"
|
||||
#endif /* FD_DEFAULT_CONF_FILENAME */
|
||||
|
||||
/* Maximum number of hooks handlers that can be registered. Make this compilation option if needed */
|
||||
#define FD_HOOK_HANDLE_LIMIT 5
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FD_IS_CONFIG */
|
||||
312
plat/diameter/freeDiameterd/main.c
Normal file
312
plat/diameter/freeDiameterd/main.c
Normal file
@@ -0,0 +1,312 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "freeDiameter-host.h"
|
||||
#include "libfdcore.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <getopt.h>
|
||||
#include <locale.h>
|
||||
|
||||
|
||||
/* forward declarations */
|
||||
//static int main_cmdline(int argc, char *argv[]);
|
||||
static void * catch_signals(void * arg);
|
||||
static pthread_t signals_thr;
|
||||
static pthread_t fd_thread;
|
||||
|
||||
static char *conffile = NULL;
|
||||
//static int gnutls_debug = 0;
|
||||
#if 0
|
||||
/* gnutls debug */
|
||||
static void fd_gnutls_debug(int level, const char * str) {
|
||||
fd_log_debug(" [gnutls:%d] %s", level, str);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* freeDiameter starting point */
|
||||
int fd_main_real(int argc, char * argv[])
|
||||
{
|
||||
int ret;
|
||||
//sigset_t sig_all;
|
||||
char conf_file[128] = {"./conf/fd_server.conf"};
|
||||
|
||||
conffile = conf_file;
|
||||
|
||||
/* Block all signals from the current thread and all its future children -- we will catch everything in catch_signals */
|
||||
/*
|
||||
sigfillset(&sig_all);
|
||||
ret = pthread_sigmask(SIG_BLOCK, &sig_all, NULL);
|
||||
ASSERT(ret == 0);
|
||||
*/
|
||||
/* Parse the command-line */
|
||||
/*
|
||||
ret = main_cmdline(argc, argv);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
*/
|
||||
/* Initialize the core library */
|
||||
ret = fd_core_initialize();
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "An error occurred during freeDiameter core library initialization.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set gnutls debug level ? */
|
||||
/*
|
||||
if (gnutls_debug) {
|
||||
gnutls_global_set_log_function((gnutls_log_func)fd_gnutls_debug);
|
||||
gnutls_global_set_log_level (gnutls_debug);
|
||||
TRACE_DEBUG(INFO, "Enabled GNUTLS debug at level %d", gnutls_debug);
|
||||
}
|
||||
*/
|
||||
/* Parse the configuration file */
|
||||
CHECK_FCT_DO( fd_core_parseconf(conffile), goto error );
|
||||
|
||||
/* Start the servers */
|
||||
CHECK_FCT_DO( fd_core_start(), goto error );
|
||||
|
||||
return 1;
|
||||
|
||||
/* Allow SIGINT and SIGTERM from this point to terminate the application */
|
||||
CHECK_POSIX_DO( pthread_create(&signals_thr, NULL, catch_signals, NULL), goto error );
|
||||
|
||||
TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized.");
|
||||
|
||||
/* Now, just wait for termination */
|
||||
CHECK_FCT( fd_core_wait_shutdown_complete() );
|
||||
|
||||
/* Just in case it was not the result of a signal, we cancel signals_thr */
|
||||
fd_thr_term(&signals_thr);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
CHECK_FCT_DO( fd_core_shutdown(), );
|
||||
CHECK_FCT( fd_core_wait_shutdown_complete() );
|
||||
fd_thr_term(&signals_thr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd_main(int argc, char * argv[])
|
||||
{
|
||||
|
||||
CHECK_POSIX_DO( pthread_create(&fd_thread, NULL, fd_main_real , NULL), return 0 );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Display package version */
|
||||
static void main_version_core(void)
|
||||
{
|
||||
printf("%s, version %s\n", FD_PROJECT_NAME, fd_core_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://www.freediameter.net/\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 (" DEFAULT_CONF_PATH "/" FD_DEFAULT_CONF_FILENAME ").\n");
|
||||
printf( "\nDebug:\n"
|
||||
" These options are mostly useful for developers\n"
|
||||
" -l, --dbglocale Set the locale for error messages\n"
|
||||
" -d, --debug Increase verbosity of debug messages if default logger is used\n"
|
||||
" -q, --quiet Decrease verbosity if default logger is used\n"
|
||||
" -f, --dbg_func <func> Enable all traces within the function <func>\n"
|
||||
" -F, --dbg_file <file.c> Enable all traces within the file <file.c> (basename match)\n"
|
||||
" --dbg_gnutls <int> Enable GNU TLS debug at level <int>\n"
|
||||
);
|
||||
}
|
||||
#if 0
|
||||
/* Parse the command-line */
|
||||
static int main_cmdline(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
int option_index = 0;
|
||||
char * locale;
|
||||
|
||||
struct option long_options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "config", required_argument, NULL, 'c' },
|
||||
{ "debug", no_argument, NULL, 'd' },
|
||||
{ "quiet", no_argument, NULL, 'q' },
|
||||
{ "dbglocale", optional_argument, NULL, 'l' },
|
||||
{ "dbg_func", required_argument, NULL, 'f' },
|
||||
{ "dbg_file", required_argument, NULL, 'F' },
|
||||
{ "dbg_gnutls", required_argument, NULL, 'g' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
/* Loop on arguments */
|
||||
while (1) {
|
||||
c = getopt_long (argc, argv, "hVc:dql:f:F:g:", 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.. */
|
||||
if (optarg == NULL ) {
|
||||
fprintf(stderr, "Missing argument with --config directive\n");
|
||||
return EINVAL;
|
||||
}
|
||||
conffile = optarg;
|
||||
break;
|
||||
|
||||
case 'l': /* Change the locale. */
|
||||
locale = setlocale(LC_ALL, optarg?:"");
|
||||
if (!locale) {
|
||||
fprintf(stderr, "Unable to set locale (%s)\n", optarg);
|
||||
return EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd': /* Increase verbosity of debug messages. */
|
||||
fd_g_debug_lvl--;
|
||||
break;
|
||||
|
||||
case 'f': /* Full debug for the function with this name. */
|
||||
#ifdef DEBUG
|
||||
fd_debug_one_function = optarg;
|
||||
fd_g_debug_lvl = FD_LOG_DEBUG;
|
||||
#else /* DEBUG */
|
||||
fprintf(stderr, "Error: must compile with DEBUG support to use --dbg_func feature!\n");
|
||||
return EINVAL;
|
||||
#endif /* DEBUG */
|
||||
break;
|
||||
|
||||
case 'F': /* Full debug for the file with this name. */
|
||||
#ifdef DEBUG
|
||||
fd_debug_one_file = basename(optarg);
|
||||
fd_g_debug_lvl = FD_LOG_DEBUG;
|
||||
#else /* DEBUG */
|
||||
fprintf(stderr, "Error: must compile with DEBUG support to use --dbg_file feature!\n");
|
||||
return EINVAL;
|
||||
#endif /* DEBUG */
|
||||
break;
|
||||
|
||||
case 'g': /* Set a debug level and function for GNU TLS calls. */
|
||||
gnutls_debug = (int)atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'q': /* Decrease verbosity then remove debug messages. */
|
||||
fd_g_debug_lvl++;
|
||||
break;
|
||||
|
||||
case '?': /* Invalid option. */
|
||||
/* `getopt_long' already printed an error message. */
|
||||
fprintf(stderr, "getopt_long found an invalid character\n");
|
||||
return EINVAL;
|
||||
|
||||
default: /* bug: option not considered. */
|
||||
fprintf(stderr, "A command-line option is missing in parser: %c\n", c);
|
||||
ASSERT(0);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
/* Handle some signals */
|
||||
static void * catch_signals(void * arg)
|
||||
{
|
||||
sigset_t ss;
|
||||
fd_log_threadname ( "signals catcher" );
|
||||
|
||||
sigemptyset(&ss);
|
||||
|
||||
/* Signals that terminate the daemon */
|
||||
sigaddset(&ss, SIGTERM);
|
||||
sigaddset(&ss, SIGINT);
|
||||
|
||||
/* Signals that send an event */
|
||||
sigaddset(&ss, SIGUSR1);
|
||||
sigaddset(&ss, SIGUSR2);
|
||||
|
||||
/* We unblock all other signals, so that their default handler is used (such as SIGTSTP) */
|
||||
CHECK_SYS_DO( pthread_sigmask( SIG_SETMASK, &ss, NULL ), goto out );
|
||||
|
||||
/* Now loop on the reception of the signal */
|
||||
while (1) {
|
||||
int sig, *ps;
|
||||
|
||||
/* Wait to receive the next signal */
|
||||
CHECK_POSIX_DO( sigwait(&ss, &sig), break );
|
||||
|
||||
TRACE_DEBUG(FULL, "Signal %d caught", sig);
|
||||
|
||||
switch (sig) {
|
||||
case SIGUSR1:
|
||||
case SIGUSR2:
|
||||
CHECK_MALLOC_DO( ps = malloc(sizeof(int)), goto out);
|
||||
*ps = sig;
|
||||
CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TRIGGER, sizeof(int), ps), goto out );
|
||||
break;
|
||||
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
CHECK_FCT_DO( fd_core_shutdown(), goto out );
|
||||
|
||||
}
|
||||
}
|
||||
out:
|
||||
/* Better way to handle this ? */
|
||||
ASSERT(0);
|
||||
return NULL;
|
||||
}
|
||||
72
plat/diameter/include/freeDiameter/extension.h
Normal file
72
plat/diameter/include/freeDiameter/extension.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#ifndef _EXTENSION_H
|
||||
#define _EXTENSION_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Include definition of freeDiameter API */
|
||||
#include "freeDiameter-host.h"
|
||||
#include "libfdcore.h"
|
||||
|
||||
/* Macro that define the entry point of the extension */
|
||||
#define EXTENSION_ENTRY(_name, _function, _depends...) \
|
||||
const char *fd_ext_depends[] = { _name , ## _depends , NULL }; \
|
||||
static int extension_loaded = 0; \
|
||||
int fd_ext_init(int major, int minor, char * conffile) { \
|
||||
if ((major != FD_PROJECT_VERSION_MAJOR) \
|
||||
|| (minor != FD_PROJECT_VERSION_MINOR)) { \
|
||||
TRACE_ERROR("This extension (" _name ") was compiled for a different version of freeDiameter."); \
|
||||
TRACE_DEBUG(INFO, "daemon %d.%d != ext %d.%d", \
|
||||
major, minor, \
|
||||
FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR); \
|
||||
return EINVAL; \
|
||||
} \
|
||||
if (extension_loaded) { \
|
||||
TRACE_ERROR("Extension (" _name ") cannot be loaded twice!"); \
|
||||
return ENOTSUP; \
|
||||
} \
|
||||
extension_loaded++; \
|
||||
return (_function)(conffile); \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EXTENSION_H */
|
||||
106
plat/diameter/include/freeDiameter/freeDiameter-host.h.in
Normal file
106
plat/diameter/include/freeDiameter/freeDiameter-host.h.in
Normal file
@@ -0,0 +1,106 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/* Configuration from compile-time */
|
||||
#ifndef FD_IS_CONFIG
|
||||
#define FD_IS_CONFIG
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#cmakedefine HAVE_NTOHLL
|
||||
#cmakedefine HAVE_MALLOC_H
|
||||
#cmakedefine HAVE_SIGNALENT_H
|
||||
#cmakedefine HAVE_AI_ADDRCONFIG
|
||||
#cmakedefine HAVE_CLOCK_GETTIME
|
||||
#cmakedefine HAVE_STRNDUP
|
||||
#cmakedefine HAVE_PTHREAD_BAR
|
||||
|
||||
#cmakedefine HOST_BIG_ENDIAN @HOST_BIG_ENDIAN@
|
||||
|
||||
#cmakedefine DISABLE_SCTP
|
||||
#cmakedefine DEBUG_SCTP
|
||||
#cmakedefine DEBUG_WITH_META
|
||||
#cmakedefine SCTP_USE_MAPPED_ADDRESSES
|
||||
#cmakedefine SCTP_CONNECTX_4_ARGS
|
||||
#cmakedefine SKIP_DLCLOSE
|
||||
#cmakedefine DIAMID_IDNA_IGNORE
|
||||
#cmakedefine DIAMID_IDNA_REJECT
|
||||
#cmakedefine DISABLE_PEER_EXPIRY
|
||||
#cmakedefine WORKAROUND_ACCEPT_INVALID_VSAI
|
||||
#cmakedefine GNUTLS_VERSION_210
|
||||
#cmakedefine GNUTLS_VERSION_212
|
||||
#cmakedefine GNUTLS_VERSION_300
|
||||
#cmakedefine GNUTLS_VERSION_310
|
||||
|
||||
#cmakedefine ERRORS_ON_TODO
|
||||
#cmakedefine DEBUG
|
||||
|
||||
#cmakedefine FD_PROJECT_BINARY "@FD_PROJECT_BINARY@"
|
||||
#cmakedefine FD_PROJECT_NAME "@FD_PROJECT_NAME@"
|
||||
#cmakedefine FD_PROJECT_VERSION_MAJOR @FD_PROJECT_VERSION_MAJOR@
|
||||
#ifndef FD_PROJECT_VERSION_MAJOR
|
||||
# define FD_PROJECT_VERSION_MAJOR 0
|
||||
#endif /*FD_PROJECT_VERSION_MAJOR*/
|
||||
#cmakedefine FD_PROJECT_VERSION_MINOR @FD_PROJECT_VERSION_MINOR@
|
||||
#ifndef FD_PROJECT_VERSION_MINOR
|
||||
# define FD_PROJECT_VERSION_MINOR 0
|
||||
#endif /*FD_PROJECT_VERSION_MINOR*/
|
||||
#cmakedefine FD_PROJECT_VERSION_REV @FD_PROJECT_VERSION_REV@
|
||||
#ifndef FD_PROJECT_VERSION_REV
|
||||
# define FD_PROJECT_VERSION_REV 0
|
||||
#endif /*FD_PROJECT_VERSION_REV*/
|
||||
#cmakedefine FD_PROJECT_VERSION_API @FD_PROJECT_VERSION_API@
|
||||
#ifndef FD_PROJECT_VERSION_API
|
||||
# define FD_PROJECT_VERSION_API 0
|
||||
#endif /*FD_PROJECT_VERSION_API*/
|
||||
#cmakedefine FD_PROJECT_COPYRIGHT "@FD_PROJECT_COPYRIGHT@"
|
||||
|
||||
#cmakedefine DEFAULT_CONF_PATH "@DEFAULT_CONF_PATH@"
|
||||
#cmakedefine DEFAULT_EXTENSIONS_PATH "@DEFAULT_EXTENSIONS_PATH@"
|
||||
|
||||
#ifndef FD_DEFAULT_CONF_FILENAME
|
||||
#define FD_DEFAULT_CONF_FILENAME "freeDiameter.conf"
|
||||
#endif /* FD_DEFAULT_CONF_FILENAME */
|
||||
|
||||
/* Maximum number of hooks handlers that can be registered. Make this compilation option if needed */
|
||||
#define FD_HOOK_HANDLE_LIMIT 5
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FD_IS_CONFIG */
|
||||
1216
plat/diameter/include/freeDiameter/libfdcore.h
Normal file
1216
plat/diameter/include/freeDiameter/libfdcore.h
Normal file
File diff suppressed because it is too large
Load Diff
3254
plat/diameter/include/freeDiameter/libfdproto.h
Normal file
3254
plat/diameter/include/freeDiameter/libfdproto.h
Normal file
File diff suppressed because it is too large
Load Diff
3
plat/diameter/include/freeDiameter/version.h.in
Normal file
3
plat/diameter/include/freeDiameter/version.h.in
Normal file
@@ -0,0 +1,3 @@
|
||||
/* Following variable is expended at build time based on the result of "hg id" command */
|
||||
#cmakedefine FD_PROJECT_VERSION_HG
|
||||
#define FD_PROJECT_VERSION_HG_VAL "@FD_PROJECT_VERSION_HG@"
|
||||
159
plat/diameter/include/gy_message.h
Normal file
159
plat/diameter/include/gy_message.h
Normal file
@@ -0,0 +1,159 @@
|
||||
#ifndef _GY_MSG_H
|
||||
#define _GY_MSG_H
|
||||
|
||||
#define MAX_GY_PORT 16384// 8192
|
||||
#define INVALID_GY_PORT 0xFFFF
|
||||
|
||||
#define NUMBER_LEN 32
|
||||
#define GY_APN_LEN 64
|
||||
//#define ADDRESS_LEN 64
|
||||
#define CONTEXT_ID_LEN 128
|
||||
|
||||
typedef enum GY_MSG_TYPE
|
||||
{
|
||||
GY_MSG_CCR,
|
||||
GY_MSG_CCA,
|
||||
}_GY_MSG_TYPE;
|
||||
|
||||
typedef enum SERVICE_TYPE
|
||||
{
|
||||
ST_CS_VOICE,
|
||||
ST_CS_SMS,
|
||||
ST_CS_VEDIO,
|
||||
ST_PS_DATA,
|
||||
ST_PS_VEDIO,
|
||||
}_SERVICE_TYPE;
|
||||
|
||||
typedef enum REQUEST_TYPE
|
||||
{
|
||||
RT_INITIAL_REQUEST=1,
|
||||
RT_UPDATE_REQUEST,
|
||||
RT_TERMINATE_REQUEST,
|
||||
RT_EVENT_REQUEST,
|
||||
}_REQUEST_TYPE;
|
||||
|
||||
typedef enum REQUEST_ACTION
|
||||
{
|
||||
RA_DIRECT_DEBITING = 0,
|
||||
RA_REFUND_ACCOUNT = 1,
|
||||
RA_CHECK_BALANCE = 2,
|
||||
RA_PRICE_ENQUIRY = 3,
|
||||
}_REQUEST_ACTION;
|
||||
|
||||
typedef enum CHECK_BALANCE_RESULT
|
||||
{
|
||||
CBR_ENOUGH_CREDIT = 0,
|
||||
CBR_NO_CREDIT = 1,
|
||||
}_CHECK_BALANCE_RESULT;
|
||||
|
||||
typedef enum REPORTING_REASON
|
||||
{
|
||||
RR_THRESHOLD = 0,
|
||||
RR_QHT = 1,
|
||||
RR_FINAL = 2,
|
||||
RR_QUOTA_EXHAUSTED = 3,
|
||||
RR_VALIDITY_TIME = 4,
|
||||
RR_OTHER_QUOTA_TYPE = 5,
|
||||
RR_RATING_CONDITION_CHANGE = 6,
|
||||
RR_FORCED_REAUTHORISATION = 7,
|
||||
RR_POOL_EXHAUSTED = 8,
|
||||
}_REPORTING_REASON;
|
||||
|
||||
typedef struct gy_ccr
|
||||
{
|
||||
|
||||
char caller[NUMBER_LEN];
|
||||
char called[NUMBER_LEN];
|
||||
char smsc[NUMBER_LEN];
|
||||
char origin_caller[NUMBER_LEN];
|
||||
char msc_addr[NUMBER_LEN];
|
||||
char vlr_number[NUMBER_LEN];
|
||||
char imsi[NUMBER_LEN];
|
||||
char apn[GY_APN_LEN];
|
||||
char cellid[16];
|
||||
int sgsn_ip;
|
||||
int ggsn_ip;
|
||||
char request_action;
|
||||
char cellid_presented;
|
||||
//char mscc_presented;
|
||||
char role_of_node;
|
||||
//long balance_to_check;
|
||||
float req_service_unit;
|
||||
int service_key;
|
||||
int reporting_reason;
|
||||
int sent_msg_num;
|
||||
long used_unit;
|
||||
}_gy_ccr;
|
||||
|
||||
typedef struct gy_cca
|
||||
{
|
||||
|
||||
int result;
|
||||
int check_balance_result;
|
||||
long grant_value;
|
||||
long volume_threshold;
|
||||
long time_threshold;
|
||||
int is_final;
|
||||
}_gy_cca;
|
||||
|
||||
typedef struct gy_msg
|
||||
{
|
||||
int fd_port;
|
||||
int app_port;
|
||||
enum GY_MSG_TYPE msg_type;
|
||||
enum SERVICE_TYPE service_type;
|
||||
enum REQUEST_TYPE request_type;
|
||||
int request_number;
|
||||
int service_identifier;
|
||||
int rating_group;
|
||||
char cxt_id[CONTEXT_ID_LEN];
|
||||
struct msg_body
|
||||
{
|
||||
_gy_ccr ccr;
|
||||
_gy_cca cca;
|
||||
}msg_body;
|
||||
|
||||
}_gy_msg;
|
||||
|
||||
typedef struct gy_port
|
||||
{
|
||||
int used_flag;
|
||||
int index;
|
||||
long updated_ts;
|
||||
int app_port;
|
||||
char context_id[CONTEXT_ID_LEN];
|
||||
enum SERVICE_TYPE service_type;
|
||||
int request_number;
|
||||
int as_client;
|
||||
}_gy_port;
|
||||
|
||||
typedef struct gy_space
|
||||
{
|
||||
int cur_index;
|
||||
int used_ports;
|
||||
_gy_port gy_port[MAX_GY_PORT];
|
||||
}_gy_space;
|
||||
|
||||
typedef struct gy_msg_stat
|
||||
{
|
||||
int ccr;
|
||||
int ccr_init;
|
||||
int ccr_update;
|
||||
int ccr_terminate;
|
||||
int ccr_event;
|
||||
int cca;
|
||||
int cca_init;
|
||||
int cca_update;
|
||||
int cca_terminate;
|
||||
int cca_event;
|
||||
}_gy_msg_stat;
|
||||
|
||||
typedef struct gy_stat
|
||||
{
|
||||
|
||||
_gy_msg_stat send_stat;
|
||||
_gy_msg_stat recv_stat;
|
||||
}_gy_stat;
|
||||
|
||||
|
||||
#endif
|
||||
152
plat/diameter/libfdcore/apps.c
Normal file
152
plat/diameter/libfdcore/apps.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2011, 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 "fdcore-internal.h"
|
||||
|
||||
/* Merge information into a list of apps */
|
||||
int fd_app_merge(struct fd_list * list, application_id_t aid, vendor_id_t vid, int auth, int acct)
|
||||
{
|
||||
struct fd_list * li;
|
||||
int skip = 0;
|
||||
|
||||
/* List is ordered by appid. Avoid duplicates */
|
||||
for (li = list; li->next != list; li = li->next) {
|
||||
struct fd_app * na = (struct fd_app *)(li->next);
|
||||
if (na->appid < aid)
|
||||
continue;
|
||||
|
||||
if (na->appid > aid)
|
||||
break;
|
||||
|
||||
/* Otherwise, we merge with existing entry -- ignore vendor id in this case */
|
||||
skip = 1;
|
||||
|
||||
if (auth)
|
||||
na->flags.auth = 1;
|
||||
if (acct)
|
||||
na->flags.acct = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!skip) {
|
||||
struct fd_app * new = NULL;
|
||||
|
||||
CHECK_MALLOC( new = malloc(sizeof(struct fd_app)) );
|
||||
memset(new, 0, sizeof(struct fd_app));
|
||||
fd_list_init(&new->chain, NULL);
|
||||
new->flags.auth = (auth ? 1 : 0);
|
||||
new->flags.acct = (acct ? 1 : 0);
|
||||
new->vndid = vid;
|
||||
new->appid = aid;
|
||||
fd_list_insert_after(li, &new->chain);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if a given application id is in a list */
|
||||
int fd_app_check(struct fd_list * list, application_id_t aid, struct fd_app **detail)
|
||||
{
|
||||
struct fd_list * li;
|
||||
|
||||
TRACE_ENTRY("%p %d %p", list, aid, detail);
|
||||
CHECK_PARAMS(list && detail);
|
||||
|
||||
*detail = NULL;
|
||||
|
||||
/* Search in the list */
|
||||
for (li = list->next; li != list; li = li->next) {
|
||||
struct fd_app * a = (struct fd_app *)li;
|
||||
if (a->appid < aid)
|
||||
continue;
|
||||
|
||||
if (a->appid == aid)
|
||||
*detail = a;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if two lists have at least one common application */
|
||||
int fd_app_check_common(struct fd_list * list1, struct fd_list * list2, int * common_found)
|
||||
{
|
||||
struct fd_list * li1, *li2;
|
||||
|
||||
TRACE_ENTRY("%p %p %p", list1, list2, common_found);
|
||||
CHECK_PARAMS( list1 && list2 && common_found );
|
||||
|
||||
/* Both lists are ordered, so advance both pointers at the same time */
|
||||
for (li1 = list1->next, li2 = list2->next; (li1 != list1) && (li2 != list2); ) {
|
||||
struct fd_app * a1 = (struct fd_app *)li1, *a2 = (struct fd_app *)li2;
|
||||
if (a1->appid < a2->appid) {
|
||||
li1 = li1->next;
|
||||
continue;
|
||||
}
|
||||
if (a1->appid > a2->appid) {
|
||||
li2 = li2->next;
|
||||
continue;
|
||||
}
|
||||
/* They are equal, compare the applications */
|
||||
if ((a1->flags.auth && a2->flags.auth) || (a1->flags.acct && a2->flags.acct)) {
|
||||
/* found! */
|
||||
*common_found = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This application is not common, advance both lists */
|
||||
li1 = li1->next;
|
||||
li2 = li2->next;
|
||||
}
|
||||
|
||||
/* We did not find a common app */
|
||||
*common_found = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove the apps from a list */
|
||||
int fd_app_empty(struct fd_list * list)
|
||||
{
|
||||
TRACE_ENTRY("%p", list);
|
||||
CHECK_PARAMS( list );
|
||||
|
||||
while (!FD_IS_LIST_EMPTY(list)) {
|
||||
struct fd_list * li = list->next;
|
||||
fd_list_unlink(li);
|
||||
free(li);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
2045
plat/diameter/libfdcore/cnxctx.c
Normal file
2045
plat/diameter/libfdcore/cnxctx.c
Normal file
File diff suppressed because it is too large
Load Diff
153
plat/diameter/libfdcore/cnxctx.h
Normal file
153
plat/diameter/libfdcore/cnxctx.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/* This file contains the definitions for internal use in the connection context files */
|
||||
|
||||
#ifndef _CNXCTX_H
|
||||
#define _CNXCTX_H
|
||||
|
||||
/* Maximum time we allow a connection to be blocked because of head-of-the-line buffers. After this delay, connection is considered in error. */
|
||||
#define MAX_HOTL_BLOCKING_TIME 1000 /* ms */
|
||||
|
||||
/* The connection context structure */
|
||||
struct cnxctx {
|
||||
char cc_id[60]; /* The name of this connection. the first 5 chars are reserved for flags display (cc_state). */
|
||||
char cc_remid[60]; /* Id of remote peer */
|
||||
|
||||
int cc_socket; /* The socket object of the connection -- <=0 if no socket is created */
|
||||
|
||||
int cc_family; /* AF_INET or AF_INET6 (mixed) */
|
||||
int cc_proto; /* IPPROTO_TCP or IPPROTO_SCTP */
|
||||
|
||||
uint32_t cc_state; /* True if the object is being destroyed: we don't send events anymore. access with fd_cnx_getstate() */
|
||||
#define CC_STATUS_CLOSING 1
|
||||
#define CC_STATUS_ERROR 2
|
||||
#define CC_STATUS_SIGNALED 4
|
||||
#define CC_STATUS_TLS 8
|
||||
|
||||
pthread_t cc_rcvthr; /* thread for receiving messages on the connection */
|
||||
int cc_loop; /* tell the thread if it loops or stops after the first message is received */
|
||||
|
||||
struct fifo * cc_incoming; /* FIFO queue of events received on the connection, FDEVP_CNX_* */
|
||||
struct fifo * cc_alt; /* alternate fifo to send FDEVP_CNX_* events to. */
|
||||
|
||||
/* If cc_tls == true */
|
||||
struct {
|
||||
DiamId_t cn; /* If not NULL, remote certif will be checked to match this Common Name */
|
||||
int mode; /* GNUTLS_CLIENT / GNUTLS_SERVER */
|
||||
int algo; /* ALGO_HANDSHAKE_DEFAULT / ALGO_HANDSHAKE_3436 */
|
||||
gnutls_session_t session; /* Session object (stream #0 in case of SCTP) */
|
||||
} cc_tls_para;
|
||||
|
||||
/* If cc_proto == SCTP */
|
||||
struct {
|
||||
uint16_t str_out; /* Out streams */
|
||||
uint16_t str_in; /* In streams */
|
||||
uint16_t pairs; /* max number of pairs ( = min(in, out)) */
|
||||
uint16_t next; /* # of stream the next message will be sent to */
|
||||
int unordered; /* boolean telling if use of streams > 0 is permitted */
|
||||
} cc_sctp_para;
|
||||
|
||||
/* If both conditions */
|
||||
struct {
|
||||
struct sctp3436_ctx *array; /* an array of cc_sctp_para.pairs elements -- the #0 is special (session is outside)*/
|
||||
struct sr_store *sess_store; /* Session data of the master session, to resume the children sessions */
|
||||
} cc_sctp3436_data;
|
||||
};
|
||||
|
||||
void fd_cnx_markerror(struct cnxctx * conn);
|
||||
uint32_t fd_cnx_getstate(struct cnxctx * conn);
|
||||
int fd_cnx_teststate(struct cnxctx * conn, uint32_t flag);
|
||||
void fd_cnx_addstate(struct cnxctx * conn, uint32_t orstate);
|
||||
void fd_cnx_setstate(struct cnxctx * conn, uint32_t abstate);
|
||||
struct fifo * fd_cnx_target_queue(struct cnxctx * conn);
|
||||
|
||||
|
||||
/* Socket */
|
||||
ssize_t fd_cnx_s_recv(struct cnxctx * conn, void *buffer, size_t length);
|
||||
void fd_cnx_s_setto(int sock);
|
||||
|
||||
/* TLS */
|
||||
int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session);
|
||||
int fd_tls_prepare(gnutls_session_t * session, int mode, int dtls, char * priority, void * alt_creds);
|
||||
#ifndef GNUTLS_VERSION_300
|
||||
int fd_tls_verify_credentials(gnutls_session_t session, struct cnxctx * conn, int verbose);
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
|
||||
/* TCP */
|
||||
int fd_tcp_create_bind_server( int * sock, sSA * sa, socklen_t salen );
|
||||
int fd_tcp_listen( int sock );
|
||||
int fd_tcp_client( int *sock, sSA * sa, socklen_t salen );
|
||||
int fd_tcp_get_local_ep(int sock, sSS * ss, socklen_t *sl);
|
||||
int fd_tcp_get_remote_ep(int sock, sSS * ss, socklen_t *sl);
|
||||
|
||||
#ifndef DISABLE_SCTP
|
||||
/* SCTP */
|
||||
int fd_sctp_create_bind_server( int * sock, int family, struct fd_list * list, uint16_t port );
|
||||
int fd_sctp_listen( int sock );
|
||||
int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list );
|
||||
int fd_sctp_get_local_ep(int sock, struct fd_list * list);
|
||||
int fd_sctp_get_remote_ep(int sock, struct fd_list * list);
|
||||
int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary );
|
||||
ssize_t fd_sctp_sendstrv(struct cnxctx * conn, uint16_t strid, const struct iovec *iov, int iovcnt);
|
||||
int fd_sctp_recvmeta(struct cnxctx * conn, uint16_t * strid, uint8_t ** buf, size_t * len, int *event);
|
||||
|
||||
/* TLS over SCTP (multi-stream) */
|
||||
struct sctp3436_ctx {
|
||||
struct cnxctx *parent; /* for info such as socket, conn name, event list */
|
||||
uint16_t strid; /* Stream # of this session */
|
||||
struct fifo *raw_recv; /* Raw data received on this stream, for demux */
|
||||
struct {
|
||||
uint8_t *buf;
|
||||
size_t bufsz;
|
||||
size_t offset;
|
||||
} partial; /* If the pull function did not read the full content of first message in raw, it stores it here for next read call. */
|
||||
pthread_t thr; /* Thread to decrypt raw data in this pair of streams */
|
||||
gnutls_session_t session; /* TLS context using this pair of streams -- except if strid == 0, in that case session is outside the array */
|
||||
};
|
||||
|
||||
int fd_sctp3436_init(struct cnxctx * conn);
|
||||
int fd_sctp3436_handshake_others(struct cnxctx * conn, char * priority, void * alt_creds);
|
||||
int fd_sctp3436_startthreads(struct cnxctx * conn, int others);
|
||||
void fd_sctp3436_bye(struct cnxctx * conn);
|
||||
void fd_sctp3436_waitthreadsterm(struct cnxctx * conn);
|
||||
void fd_sctp3436_gnutls_deinit_others(struct cnxctx * conn);
|
||||
void fd_sctp3436_stopthreads(struct cnxctx * conn);
|
||||
void fd_sctp3436_destroy(struct cnxctx * conn);
|
||||
|
||||
#endif /* DISABLE_SCTP */
|
||||
|
||||
#endif /* _CNXCTX_H */
|
||||
|
||||
643
plat/diameter/libfdcore/config.c
Normal file
643
plat/diameter/libfdcore/config.c
Normal file
@@ -0,0 +1,643 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2015, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
#include <sys/stat.h>
|
||||
/* Configuration management */
|
||||
|
||||
#ifndef GNUTLS_DEFAULT_PRIORITY
|
||||
# define GNUTLS_DEFAULT_PRIORITY "NORMAL"
|
||||
#endif /* GNUTLS_DEFAULT_PRIORITY */
|
||||
#ifndef GNUTLS_DEFAULT_DHBITS
|
||||
# define GNUTLS_DEFAULT_DHBITS 1024
|
||||
#endif /* GNUTLS_DEFAULT_DHBITS */
|
||||
|
||||
/* Initialize the fd_g_config structure to default values -- it should already have been initialized to all-0 */
|
||||
int fd_conf_init()
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
fd_g_config->cnf_eyec = EYEC_CONFIG;
|
||||
|
||||
fd_g_config->cnf_timer_tc = 30;
|
||||
fd_g_config->cnf_timer_tw = 30;
|
||||
|
||||
fd_g_config->cnf_port = DIAMETER_PORT;
|
||||
fd_g_config->cnf_port_tls = DIAMETER_SECURE_PORT;
|
||||
fd_g_config->cnf_sctp_str = 30;
|
||||
fd_g_config->cnf_thr_srv = 10;
|
||||
fd_g_config->cnf_dispthr = 1;// = 10;
|
||||
fd_list_init(&fd_g_config->cnf_endpoints, NULL);
|
||||
fd_list_init(&fd_g_config->cnf_apps, NULL);
|
||||
#ifdef DISABLE_SCTP
|
||||
fd_g_config->cnf_flags.no_sctp = 1;
|
||||
#endif /* DISABLE_SCTP */
|
||||
|
||||
fd_g_config->cnf_orstateid = (uint32_t) time(NULL);
|
||||
|
||||
CHECK_FCT( fd_dict_init(&fd_g_config->cnf_dict) );
|
||||
CHECK_FCT( fd_fifo_new(&fd_g_config->cnf_main_ev, 0) );
|
||||
|
||||
/* TLS parameters */
|
||||
CHECK_GNUTLS_DO( gnutls_certificate_allocate_credentials (&fd_g_config->cnf_sec_data.credentials), return ENOMEM );
|
||||
CHECK_GNUTLS_DO( gnutls_dh_params_init (&fd_g_config->cnf_sec_data.dh_cache), return ENOMEM );
|
||||
#ifdef GNUTLS_VERSION_300
|
||||
CHECK_GNUTLS_DO( gnutls_x509_trust_list_init(&fd_g_config->cnf_sec_data.trustlist, 0), return ENOMEM );
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECLARE_FD_DUMP_PROTOTYPE(fd_conf_dump)
|
||||
{
|
||||
FD_DUMP_HANDLE_OFFSET();
|
||||
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "freeDiameter configuration:\n"), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Default trace level .... : %+d\n", fd_g_debug_lvl), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Configuration file ..... : %s\n", fd_g_config->cnf_file), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Diameter Identity ...... : %s (l:%zi)\n", fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Diameter Realm ......... : %s (l:%zi)\n", fd_g_config->cnf_diamrlm, fd_g_config->cnf_diamrlm_len), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Tc Timer ............... : %u\n", fd_g_config->cnf_timer_tc), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Tw Timer ............... : %u\n", fd_g_config->cnf_timer_tw), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Local port ............. : %hu\n", fd_g_config->cnf_port), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Local secure port ...... : %hu\n", fd_g_config->cnf_port_tls), return NULL);
|
||||
if (fd_g_config->cnf_port_3436) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Local SCTP TLS port .... : %hu\n", fd_g_config->cnf_port_3436), return NULL);
|
||||
}
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Number of SCTP streams . : %hu\n", fd_g_config->cnf_sctp_str), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Number of clients thr .. : %d\n", fd_g_config->cnf_thr_srv), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Number of app threads .. : %hu\n", fd_g_config->cnf_dispthr), return NULL);
|
||||
if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Local endpoints ........ : Default (use all available)\n"), return NULL);
|
||||
} else {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Local endpoints ........ : "), return NULL);
|
||||
CHECK_MALLOC_DO( fd_ep_dump( FD_DUMP_STD_PARAMS, 0, 0, &fd_g_config->cnf_endpoints ), return NULL);
|
||||
}
|
||||
if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_apps)) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Local applications ..... : (none)"), return NULL);
|
||||
} else {
|
||||
struct fd_list * li = fd_g_config->cnf_apps.next;
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Local applications ..... : "), return NULL);
|
||||
while (li != &fd_g_config->cnf_apps) {
|
||||
struct fd_app * app = (struct fd_app *)li;
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "App: %u,%s%s,Vnd:%u\t",
|
||||
app->appid,
|
||||
app->flags.auth ? "Au" : "--",
|
||||
app->flags.acct ? "Ac" : "--",
|
||||
app->vndid), return NULL);
|
||||
li = li->next;
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n Flags : - IP ........... : %s\n", fd_g_config->cnf_flags.no_ip4 ? "DISABLED" : "Enabled"), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - IPv6 ......... : %s\n", fd_g_config->cnf_flags.no_ip6 ? "DISABLED" : "Enabled"), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - Relay app .... : %s\n", fd_g_config->cnf_flags.no_fwd ? "DISABLED" : "Enabled"), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - TCP .......... : %s\n", fd_g_config->cnf_flags.no_tcp ? "DISABLED" : "Enabled"), return NULL);
|
||||
#ifdef DISABLE_SCTP
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - SCTP ......... : DISABLED (at compilation)\n"), return NULL);
|
||||
#else /* DISABLE_SCTP */
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - SCTP ......... : %s\n", fd_g_config->cnf_flags.no_sctp ? "DISABLED" : "Enabled"), return NULL);
|
||||
#endif /* DISABLE_SCTP */
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - Pref. proto .. : %s\n", fd_g_config->cnf_flags.pr_tcp ? "TCP" : "SCTP"), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - TLS method ... : %s\n", fd_g_config->cnf_flags.tls_alg ? "INBAND" : "Separate port"), return NULL);
|
||||
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " TLS : - Certificate .. : %s\n", fd_g_config->cnf_sec_data.cert_file ?: "(NONE)"), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - Private key .. : %s\n", fd_g_config->cnf_sec_data.key_file ?: "(NONE)"), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - CA (trust) ... : %s (%d certs)\n", fd_g_config->cnf_sec_data.ca_file ?: "(none)", fd_g_config->cnf_sec_data.ca_file_nr), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - CRL .......... : %s\n", fd_g_config->cnf_sec_data.crl_file ?: "(none)"), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - Priority ..... : %s\n", fd_g_config->cnf_sec_data.prio_string ?: "(default: '" GNUTLS_DEFAULT_PRIORITY "')"), return NULL);
|
||||
if (fd_g_config->cnf_sec_data.dh_file) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - DH file ...... : %s\n", fd_g_config->cnf_sec_data.dh_file), return NULL);
|
||||
} else {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " - DH bits ...... : %d\n", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS), return NULL);
|
||||
}
|
||||
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " Origin-State-Id ........ : %u", fd_g_config->cnf_orstateid), return NULL);
|
||||
|
||||
return *buf;
|
||||
}
|
||||
|
||||
/* read contents of a file opened in "rb" mode and alloc this data into a gnutls_datum_t (must be freed afterwards) */
|
||||
int fd_conf_stream_to_gnutls_datum(FILE * pemfile, gnutls_datum_t *out)
|
||||
{
|
||||
size_t alloc = 0;
|
||||
|
||||
CHECK_PARAMS( pemfile && out );
|
||||
memset(out, 0, sizeof(gnutls_datum_t));
|
||||
|
||||
do {
|
||||
uint8_t * realloced = NULL;
|
||||
size_t read = 0;
|
||||
|
||||
if (alloc < out->size + BUFSIZ + 1) {
|
||||
alloc += alloc / 2 + BUFSIZ + 1;
|
||||
CHECK_MALLOC_DO( realloced = realloc(out->data, alloc),
|
||||
{
|
||||
free(out->data);
|
||||
return ENOMEM;
|
||||
} )
|
||||
out->data = realloced;
|
||||
}
|
||||
|
||||
read = fread( out->data + out->size, 1, alloc - out->size - 1, pemfile );
|
||||
out->size += read;
|
||||
|
||||
if (ferror(pemfile)) {
|
||||
int err = errno;
|
||||
TRACE_DEBUG(INFO, "An error occurred while reading file: %s", strerror(err));
|
||||
return err;
|
||||
}
|
||||
} while (!feof(pemfile));
|
||||
|
||||
out->data[out->size] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef GNUTLS_VERSION_300
|
||||
/* inspired from GnuTLS manual */
|
||||
static int fd_conf_print_details_func (gnutls_x509_crt_t cert,
|
||||
gnutls_x509_crt_t issuer, gnutls_x509_crl_t crl,
|
||||
unsigned int verification_output)
|
||||
{
|
||||
char name[512];
|
||||
char issuer_name[512];
|
||||
size_t name_size;
|
||||
size_t issuer_name_size;
|
||||
|
||||
if (!TRACE_BOOL(GNUTLS_DBG_LEVEL))
|
||||
return 0;
|
||||
|
||||
issuer_name_size = sizeof (issuer_name);
|
||||
gnutls_x509_crt_get_issuer_dn (cert, issuer_name, &issuer_name_size);
|
||||
|
||||
name_size = sizeof (name);
|
||||
gnutls_x509_crt_get_dn (cert, name, &name_size);
|
||||
|
||||
fd_log_debug("\tSubject: %s", name);
|
||||
fd_log_debug("\tIssuer: %s", issuer_name);
|
||||
|
||||
if (issuer != NULL)
|
||||
{
|
||||
issuer_name_size = sizeof (issuer_name);
|
||||
gnutls_x509_crt_get_dn (issuer, issuer_name, &issuer_name_size);
|
||||
|
||||
fd_log_debug("\tVerified against: %s", issuer_name);
|
||||
}
|
||||
|
||||
if (crl != NULL)
|
||||
{
|
||||
issuer_name_size = sizeof (issuer_name);
|
||||
gnutls_x509_crl_get_issuer_dn (crl, issuer_name, &issuer_name_size);
|
||||
|
||||
fd_log_debug("\tVerified against CRL of: %s", issuer_name);
|
||||
}
|
||||
|
||||
fd_log_debug("\tVerification output: %x", verification_output);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
|
||||
#ifndef GNUTLS_VERSION_300
|
||||
GCC_DIAG_OFF("-Wdeprecated-declarations")
|
||||
#endif /* !GNUTLS_VERSION_300 */
|
||||
/* Parse the configuration file (using the yacc parser) */
|
||||
int fd_conf_parse()
|
||||
{
|
||||
FILE * fddin;
|
||||
const char * orig = NULL;
|
||||
|
||||
/* Attempt to find the configuration file */
|
||||
if (!fd_g_config->cnf_file)
|
||||
fd_g_config->cnf_file = FD_DEFAULT_CONF_FILENAME;
|
||||
|
||||
fddin = fopen(fd_g_config->cnf_file, "r");
|
||||
if ((fddin == NULL) && (*fd_g_config->cnf_file != '/')) {
|
||||
char * new_cnf = NULL;
|
||||
/* We got a relative path, attempt to add the default directory prefix */
|
||||
orig = fd_g_config->cnf_file;
|
||||
CHECK_MALLOC( new_cnf = malloc(strlen(orig) + strlen(DEFAULT_CONF_PATH) + 2) ); /* we will not free it, but not important */
|
||||
sprintf( new_cnf, DEFAULT_CONF_PATH "/%s", orig );
|
||||
fd_g_config->cnf_file = new_cnf;
|
||||
fddin = fopen(fd_g_config->cnf_file, "r");
|
||||
}
|
||||
if (fddin == NULL) {
|
||||
int ret = errno;
|
||||
LOG_F("Unable to open configuration file for reading; tried the following locations: %s%s%s; Error: %s",
|
||||
orig ?: "", orig? " and " : "", fd_g_config->cnf_file, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* call yacc parser */
|
||||
TRACE_DEBUG (FULL, "Parsing configuration file: %s", fd_g_config->cnf_file);
|
||||
CHECK_FCT( fddparse(fd_g_config) );
|
||||
|
||||
/* close the file */
|
||||
fclose(fddin);
|
||||
|
||||
/* Check that TLS private key was given */
|
||||
if (! fd_g_config->cnf_sec_data.key_file) {
|
||||
/* If TLS is not enabled, we allow empty TLS configuration */
|
||||
if ((fd_g_config->cnf_port_tls == 0) && (fd_g_config->cnf_flags.tls_alg == 0)) {
|
||||
LOG_N("TLS is disabled, this is *NOT* a recommended practice! Diameter protocol conveys highly sensitive information on your users.");
|
||||
fd_g_config->cnf_sec_data.tls_disabled = 1;
|
||||
} else {
|
||||
LOG_F( "Missing private key configuration for TLS. Please provide the TLS_cred configuration directive.");
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Resolve hostname if not provided */
|
||||
if (fd_g_config->cnf_diamid == NULL) {
|
||||
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) {
|
||||
TRACE_ERROR( "Error resolving local FQDN : '%s' : %s"
|
||||
". Please provide Identity in configuration file.",
|
||||
buf, gai_strerror(ret));
|
||||
return EINVAL;
|
||||
}
|
||||
fd_g_config->cnf_diamid = info->ai_canonname;
|
||||
CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamid, &fd_g_config->cnf_diamid_len, 1) );
|
||||
freeaddrinfo(info);
|
||||
} else {
|
||||
CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamid, &fd_g_config->cnf_diamid_len, 0) );
|
||||
}
|
||||
|
||||
/* Handle the realm part */
|
||||
if (fd_g_config->cnf_diamrlm == NULL) {
|
||||
char * start = NULL;
|
||||
|
||||
/* Check the diameter identity is a fqdn */
|
||||
start = strchr(fd_g_config->cnf_diamid, '.');
|
||||
if ((start == NULL) || (start[1] == '\0')) {
|
||||
TRACE_ERROR( "Unable to extract realm from the Identity '%s'."
|
||||
" Please fix your Identity setting or provide Realm.",
|
||||
fd_g_config->cnf_diamid);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
fd_g_config->cnf_diamrlm = start + 1;
|
||||
CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamrlm, &fd_g_config->cnf_diamrlm_len, 1) );
|
||||
} else {
|
||||
CHECK_FCT( fd_os_validate_DiameterIdentity(&fd_g_config->cnf_diamrlm, &fd_g_config->cnf_diamrlm_len, 0) );
|
||||
}
|
||||
|
||||
/* Validate some flags */
|
||||
if (fd_g_config->cnf_flags.no_ip4 && fd_g_config->cnf_flags.no_ip6) {
|
||||
TRACE_ERROR( "IP and IPv6 cannot be disabled at the same time.");
|
||||
return EINVAL;
|
||||
}
|
||||
if (fd_g_config->cnf_flags.no_tcp && fd_g_config->cnf_flags.no_sctp) {
|
||||
TRACE_ERROR( "TCP and SCTP cannot be disabled at the same time.");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Validate local endpoints */
|
||||
if ((!FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) && (fd_g_config->cnf_flags.no_ip4 || fd_g_config->cnf_flags.no_ip6)) {
|
||||
struct fd_list * li;
|
||||
for ( li = fd_g_config->cnf_endpoints.next; li != &fd_g_config->cnf_endpoints; li = li->next) {
|
||||
struct fd_endpoint * ep = (struct fd_endpoint *)li;
|
||||
if ( (fd_g_config->cnf_flags.no_ip4 && (ep->sa.sa_family == AF_INET))
|
||||
||(fd_g_config->cnf_flags.no_ip6 && (ep->sa.sa_family == AF_INET6)) ) {
|
||||
char sa_buf[sSA_DUMP_STRLEN];;
|
||||
li = li->prev;
|
||||
fd_list_unlink(&ep->chain);
|
||||
fd_sa_sdump_numeric(sa_buf, &ep->sa);
|
||||
LOG_N("Info: Removing local address conflicting with the flags no_IP / no_IP6 : %s", sa_buf);
|
||||
free(ep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Configure TLS default parameters */
|
||||
if ((!fd_g_config->cnf_sec_data.tls_disabled) && (!fd_g_config->cnf_sec_data.prio_string)) {
|
||||
const char * err_pos = NULL;
|
||||
CHECK_GNUTLS_DO( gnutls_priority_init(
|
||||
&fd_g_config->cnf_sec_data.prio_cache,
|
||||
GNUTLS_DEFAULT_PRIORITY,
|
||||
&err_pos),
|
||||
{ TRACE_ERROR("Error in priority string at position : %s", err_pos); return EINVAL; } );
|
||||
}
|
||||
|
||||
/* Verify that our certificate is valid -- otherwise remote peers will reject it */
|
||||
if (!fd_g_config->cnf_sec_data.tls_disabled) {
|
||||
int ret = 0, i;
|
||||
|
||||
gnutls_datum_t certfile;
|
||||
|
||||
gnutls_x509_crt_t * certs = NULL;
|
||||
unsigned int cert_max = 0;
|
||||
|
||||
|
||||
/* Read the certificate file */
|
||||
FILE *stream = fopen (fd_g_config->cnf_sec_data.cert_file, "rb");
|
||||
if (!stream) {
|
||||
int err = errno;
|
||||
TRACE_DEBUG(INFO, "An error occurred while opening '%s': %s", fd_g_config->cnf_sec_data.cert_file, strerror(err));
|
||||
return err;
|
||||
}
|
||||
CHECK_FCT( fd_conf_stream_to_gnutls_datum(stream, &certfile) );
|
||||
fclose(stream);
|
||||
|
||||
/* Import the certificate(s) */
|
||||
GNUTLS_TRACE( ret = gnutls_x509_crt_list_import(NULL, &cert_max, &certfile, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED) );
|
||||
if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
|
||||
CHECK_GNUTLS_DO(ret, return EINVAL);
|
||||
}
|
||||
|
||||
CHECK_MALLOC( certs = calloc(cert_max, sizeof(gnutls_x509_crt_t)) );
|
||||
CHECK_GNUTLS_DO( gnutls_x509_crt_list_import(certs, &cert_max, &certfile, GNUTLS_X509_FMT_PEM,
|
||||
#ifdef GNUTLS_VERSION_300
|
||||
GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED
|
||||
#else /* GNUTLS_VERSION_300 */
|
||||
0
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
),
|
||||
{
|
||||
TRACE_ERROR("Failed to import the data from file '%s'", fd_g_config->cnf_sec_data.cert_file);
|
||||
free(certfile.data);
|
||||
return EINVAL;
|
||||
} );
|
||||
free(certfile.data);
|
||||
|
||||
ASSERT(cert_max >= 1);
|
||||
|
||||
/* Now, verify the list against the local CA and CRL */
|
||||
|
||||
#ifdef GNUTLS_VERSION_300
|
||||
|
||||
/* We use the trust list for this purpose */
|
||||
{
|
||||
unsigned int output;
|
||||
|
||||
gnutls_x509_trust_list_verify_named_crt (
|
||||
fd_g_config->cnf_sec_data.trustlist,
|
||||
certs[0],
|
||||
fd_g_config->cnf_diamid,
|
||||
fd_g_config->cnf_diamid_len,
|
||||
0,
|
||||
&output,
|
||||
fd_conf_print_details_func);
|
||||
|
||||
/* if this certificate is not explicitly trusted verify against CAs
|
||||
*/
|
||||
if (output != 0)
|
||||
{
|
||||
gnutls_x509_trust_list_verify_crt (
|
||||
fd_g_config->cnf_sec_data.trustlist,
|
||||
certs,
|
||||
cert_max,
|
||||
0,
|
||||
&output,
|
||||
fd_conf_print_details_func);
|
||||
}
|
||||
|
||||
if (output & GNUTLS_CERT_INVALID)
|
||||
{
|
||||
fd_log_debug("TLS: Local certificate chain '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
|
||||
if (output & GNUTLS_CERT_SIGNER_NOT_FOUND)
|
||||
TRACE_ERROR(" - The certificate hasn't got a known issuer. Did you forget to specify TLS_CA ?");
|
||||
if (output & GNUTLS_CERT_SIGNER_NOT_CA)
|
||||
TRACE_ERROR(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.");
|
||||
if (output & GNUTLS_CERT_NOT_ACTIVATED)
|
||||
TRACE_ERROR(" - The certificate is not yet activated.");
|
||||
if (output & GNUTLS_CERT_EXPIRED)
|
||||
TRACE_ERROR(" - The certificate is expired.");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Now check the subject matches our hostname */
|
||||
if (!gnutls_x509_crt_check_hostname (certs[0], fd_g_config->cnf_diamid))
|
||||
{
|
||||
TRACE_ERROR("TLS: The certificate owner does not match the hostname '%s'", fd_g_config->cnf_diamid);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#else /* GNUTLS_VERSION_300 */
|
||||
|
||||
/* GnuTLS 2.x way of checking certificates */
|
||||
{
|
||||
gnutls_x509_crt_t * CA_list;
|
||||
int CA_list_length;
|
||||
|
||||
gnutls_x509_crl_t * CRL_list;
|
||||
int CRL_list_length;
|
||||
|
||||
unsigned int verify;
|
||||
time_t now;
|
||||
/*
|
||||
GNUTLS_TRACE( gnutls_certificate_get_x509_cas (fd_g_config->cnf_sec_data.credentials, &CA_list, (unsigned int *) &CA_list_length) );
|
||||
GNUTLS_TRACE( gnutls_certificate_get_x509_crls (fd_g_config->cnf_sec_data.credentials, &CRL_list, (unsigned int *) &CRL_list_length) );
|
||||
CHECK_GNUTLS_DO( gnutls_x509_crt_list_verify(certs, cert_max, CA_list, CA_list_length, CRL_list, CRL_list_length, 0, &verify),
|
||||
{
|
||||
TRACE_ERROR("Failed to verify the local certificate '%s' against local credentials. Please check your certificate is valid.", fd_g_config->cnf_sec_data.cert_file);
|
||||
return EINVAL;
|
||||
} );
|
||||
*/
|
||||
if (verify) {
|
||||
fd_log_debug("TLS: Local certificate chain '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
|
||||
if (verify & GNUTLS_CERT_INVALID)
|
||||
TRACE_ERROR(" - The certificate is not trusted (unknown CA? expired?)");
|
||||
if (verify & GNUTLS_CERT_REVOKED)
|
||||
TRACE_ERROR(" - The certificate has been revoked.");
|
||||
if (verify & GNUTLS_CERT_SIGNER_NOT_FOUND)
|
||||
TRACE_ERROR(" - The certificate hasn't got a known issuer.");
|
||||
if (verify & GNUTLS_CERT_SIGNER_NOT_CA)
|
||||
TRACE_ERROR(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.");
|
||||
if (verify & GNUTLS_CERT_INSECURE_ALGORITHM)
|
||||
TRACE_ERROR(" - The certificate signature uses a weak algorithm.");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Check the local Identity is valid with the certificate */
|
||||
if (!gnutls_x509_crt_check_hostname (certs[0], fd_g_config->cnf_diamid)) {
|
||||
TRACE_ERROR("TLS: Local certificate '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
|
||||
TRACE_ERROR(" - The certificate hostname does not match '%s'", fd_g_config->cnf_diamid);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Check validity of all the certificates in the chain */
|
||||
now = time(NULL);
|
||||
for (i = 0; i < cert_max; i++)
|
||||
{
|
||||
time_t deadline;
|
||||
|
||||
GNUTLS_TRACE( deadline = gnutls_x509_crt_get_expiration_time(certs[i]) );
|
||||
if ((deadline != (time_t)-1) && (deadline < now)) {
|
||||
TRACE_ERROR("TLS: Local certificate chain '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
|
||||
TRACE_ERROR(" - The certificate %d in the chain is expired", i);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
GNUTLS_TRACE( deadline = gnutls_x509_crt_get_activation_time(certs[i]) );
|
||||
if ((deadline != (time_t)-1) && (deadline > now)) {
|
||||
TRACE_ERROR("TLS: Local certificate chain '%s' is invalid :", fd_g_config->cnf_sec_data.cert_file);
|
||||
TRACE_ERROR(" - The certificate %d in the chain is not yet activated", i);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
|
||||
/* Everything checked OK, free the certificate list */
|
||||
for (i = 0; i < cert_max; i++)
|
||||
{
|
||||
GNUTLS_TRACE( gnutls_x509_crt_deinit (certs[i]) );
|
||||
}
|
||||
free(certs);
|
||||
|
||||
#ifdef GNUTLS_VERSION_300
|
||||
/* Use certificate verification during the handshake */
|
||||
gnutls_certificate_set_verify_function (fd_g_config->cnf_sec_data.credentials, fd_tls_verify_credentials_2);
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
|
||||
}
|
||||
|
||||
/* gnutls_certificate_set_verify_limits -- so far the default values are fine... */
|
||||
|
||||
/* DH */
|
||||
if (!fd_g_config->cnf_sec_data.tls_disabled) {
|
||||
if (fd_g_config->cnf_sec_data.dh_file) {
|
||||
gnutls_datum_t dhparams = { NULL, 0 };
|
||||
size_t alloc = 0;
|
||||
FILE *stream = fopen (fd_g_config->cnf_sec_data.dh_file, "rb");
|
||||
if (!stream) {
|
||||
int err = errno;
|
||||
TRACE_DEBUG(INFO, "An error occurred while opening '%s': %s", fd_g_config->cnf_sec_data.dh_file, strerror(err));
|
||||
return err;
|
||||
}
|
||||
do {
|
||||
uint8_t * realloced = NULL;
|
||||
size_t read = 0;
|
||||
|
||||
if (alloc < dhparams.size + BUFSIZ + 1) {
|
||||
alloc += alloc / 2 + BUFSIZ + 1;
|
||||
CHECK_MALLOC_DO( realloced = realloc(dhparams.data, alloc),
|
||||
{
|
||||
free(dhparams.data);
|
||||
return ENOMEM;
|
||||
} )
|
||||
dhparams.data = realloced;
|
||||
}
|
||||
|
||||
read = fread( dhparams.data + dhparams.size, 1, alloc - dhparams.size - 1, stream );
|
||||
dhparams.size += read;
|
||||
|
||||
if (ferror(stream)) {
|
||||
int err = errno;
|
||||
TRACE_DEBUG(INFO, "An error occurred while reading '%s': %s", fd_g_config->cnf_sec_data.dh_file, strerror(err));
|
||||
return err;
|
||||
}
|
||||
} while (!feof(stream));
|
||||
dhparams.data[dhparams.size] = '\0';
|
||||
fclose(stream);
|
||||
CHECK_GNUTLS_DO( gnutls_dh_params_import_pkcs3(
|
||||
fd_g_config->cnf_sec_data.dh_cache,
|
||||
&dhparams,
|
||||
GNUTLS_X509_FMT_PEM),
|
||||
{ TRACE_ERROR("Error in DH bits value : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
|
||||
free(dhparams.data);
|
||||
|
||||
} else {
|
||||
LOG_D( "Generating fresh Diffie-Hellman parameters of size %d (this takes some time)... ", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS);
|
||||
CHECK_GNUTLS_DO( gnutls_dh_params_generate2(
|
||||
fd_g_config->cnf_sec_data.dh_cache,
|
||||
fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS),
|
||||
{ TRACE_ERROR("Error in DH bits value : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#ifndef GNUTLS_VERSION_300
|
||||
GCC_DIAG_ON("-Wdeprecated-declarations")
|
||||
#endif /* !GNUTLS_VERSION_300 */
|
||||
|
||||
|
||||
/* Destroy contents of fd_g_config structure */
|
||||
int fd_conf_deinit()
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (!fd_g_config)
|
||||
return 0;
|
||||
|
||||
/* Free the TLS parameters */
|
||||
#ifdef GNUTLS_VERSION_300
|
||||
gnutls_x509_trust_list_deinit(fd_g_config->cnf_sec_data.trustlist, 1);
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
gnutls_priority_deinit(fd_g_config->cnf_sec_data.prio_cache);
|
||||
gnutls_dh_params_deinit(fd_g_config->cnf_sec_data.dh_cache);
|
||||
gnutls_certificate_free_credentials(fd_g_config->cnf_sec_data.credentials);
|
||||
|
||||
free(fd_g_config->cnf_sec_data.cert_file); fd_g_config->cnf_sec_data.cert_file = NULL;
|
||||
free(fd_g_config->cnf_sec_data.key_file); fd_g_config->cnf_sec_data.key_file = NULL;
|
||||
free(fd_g_config->cnf_sec_data.ca_file); fd_g_config->cnf_sec_data.ca_file = NULL;
|
||||
free(fd_g_config->cnf_sec_data.crl_file); fd_g_config->cnf_sec_data.crl_file = NULL;
|
||||
free(fd_g_config->cnf_sec_data.prio_string); fd_g_config->cnf_sec_data.prio_string = NULL;
|
||||
free(fd_g_config->cnf_sec_data.dh_file); fd_g_config->cnf_sec_data.dh_file = NULL;
|
||||
|
||||
/* Destroy dictionary */
|
||||
CHECK_FCT_DO( fd_dict_fini(&fd_g_config->cnf_dict), );
|
||||
|
||||
/* Destroy the main event queue */
|
||||
CHECK_FCT_DO( fd_fifo_del(&fd_g_config->cnf_main_ev), );
|
||||
|
||||
/* Destroy the local endpoints and applications */
|
||||
CHECK_FCT_DO(fd_ep_filter(&fd_g_config->cnf_endpoints, 0 ), );
|
||||
CHECK_FCT_DO(fd_app_empty(&fd_g_config->cnf_apps ), );
|
||||
|
||||
/* Destroy the local identity */
|
||||
free(fd_g_config->cnf_diamid); fd_g_config->cnf_diamid = NULL;
|
||||
free(fd_g_config->cnf_diamrlm); fd_g_config->cnf_diamrlm = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
403
plat/diameter/libfdcore/core.c
Normal file
403
plat/diameter/libfdcore/core.c
Normal file
@@ -0,0 +1,403 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
GCC_DIAG_OFF("-Wdeprecated-declarations")
|
||||
#include <gcrypt.h>
|
||||
GCC_DIAG_ON("-Wdeprecated-declarations")
|
||||
|
||||
/* hash: session-id===>port id */
|
||||
GHashTable *g_sess_hash = NULL;
|
||||
|
||||
/* The static configuration structure */
|
||||
static struct fd_config g_conf;
|
||||
struct fd_config * fd_g_config = NULL;
|
||||
|
||||
/* gcrypt functions to support posix threads */
|
||||
#ifndef GNUTLS_VERSION_210
|
||||
GCRY_THREAD_OPTION_PTHREAD_IMPL;
|
||||
#endif /* GNUTLS_VERSION_210 */
|
||||
|
||||
/* Thread that process incoming events on the main queue -- and terminates the framework when requested */
|
||||
static pthread_t core_runner = (pthread_t)NULL;
|
||||
|
||||
/* Signal extensions when the framework is completely initialized (they are waiting in fd_core_waitstartcomplete()) */
|
||||
static enum core_state {
|
||||
CORE_NOT_INIT, /* initial state */
|
||||
CORE_LIBS_INIT, /* fd_core_initialize was called */
|
||||
CORE_CONF_READY,/* Configuration was parsed, extensions are loaded */
|
||||
CORE_RUNNING, /* Servers and clients are started, core_runner thread is running */
|
||||
CORE_SHUTDOWN, /* The framework is terminating all objects */
|
||||
CORE_TERM /* Shutdown complete. */
|
||||
} core_state = CORE_NOT_INIT;
|
||||
static pthread_mutex_t core_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t core_cnd = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
static enum core_state core_state_get(void)
|
||||
{
|
||||
enum core_state cur_state;
|
||||
CHECK_POSIX_DO( pthread_mutex_lock( &core_mtx ), );
|
||||
cur_state = core_state;
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock( &core_mtx ), );
|
||||
return cur_state;
|
||||
}
|
||||
|
||||
static void core_state_set(enum core_state newstate)
|
||||
{
|
||||
CHECK_POSIX_DO( pthread_mutex_lock( &core_mtx ), );
|
||||
LOG_D("Core state: %d -> %d", core_state, newstate);
|
||||
core_state = newstate;
|
||||
CHECK_POSIX_DO( pthread_cond_broadcast( &core_cnd ), );
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock( &core_mtx ), );
|
||||
}
|
||||
|
||||
static int core_state_wait(enum core_state waitstate)
|
||||
{
|
||||
int ret = 0;
|
||||
CHECK_POSIX( pthread_mutex_lock( &core_mtx ));
|
||||
pthread_cleanup_push( fd_cleanup_mutex, &core_mtx );
|
||||
while (waitstate > core_state) {
|
||||
CHECK_POSIX_DO(ret = pthread_cond_wait(&core_cnd, &core_mtx), break);
|
||||
}
|
||||
pthread_cleanup_pop( 0 );
|
||||
CHECK_POSIX( pthread_mutex_unlock( &core_mtx ));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void core_shutdown(void)
|
||||
{
|
||||
LOG_N( FD_PROJECT_BINARY " framework is stopping...");
|
||||
fd_log_threadname("fD Core Shutdown");
|
||||
|
||||
/* cleanups */
|
||||
CHECK_FCT_DO( fd_servers_stop(), /* Stop accepting new connections */ );
|
||||
CHECK_FCT_DO( fd_rtdisp_cleanstop(), /* Stop dispatch thread(s) after a clean loop if possible */ );
|
||||
CHECK_FCT_DO( fd_peer_fini(), /* Stop all connections */ );
|
||||
CHECK_FCT_DO( fd_rtdisp_fini(), /* Stop routing threads and destroy routing queues */ );
|
||||
|
||||
CHECK_FCT_DO( fd_ext_term(), /* Cleanup all extensions */ );
|
||||
CHECK_FCT_DO( fd_rtdisp_cleanup(), /* destroy remaining handlers */ );
|
||||
|
||||
GNUTLS_TRACE( gnutls_global_deinit() );
|
||||
|
||||
CHECK_FCT_DO( fd_conf_deinit(), );
|
||||
|
||||
CHECK_FCT_DO( fd_event_trig_fini(), );
|
||||
|
||||
fd_log_debug(FD_PROJECT_BINARY " framework is terminated.");
|
||||
|
||||
fd_libproto_fini();
|
||||
|
||||
g_hash_table_destroy(g_sess_hash);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void * core_runner_thread(void * arg)
|
||||
{
|
||||
char cause[128]={"no cb"};
|
||||
|
||||
fd_log_threadname("fD Core Runner");
|
||||
|
||||
core_state_wait(CORE_RUNNING);
|
||||
|
||||
/* Handle events incoming on the main event queue */
|
||||
while (1) {
|
||||
int code; size_t sz; void * data;
|
||||
CHECK_FCT_DO( fd_event_get(fd_g_config->cnf_main_ev, &code, &sz, &data), break );
|
||||
switch (code) {
|
||||
case FDEV_TRIGGER:
|
||||
{
|
||||
int tv, *p;
|
||||
CHECK_PARAMS_DO( sz == sizeof(int),
|
||||
{
|
||||
TRACE_DEBUG(NONE, "Internal error: got FDEV_TRIGGER without trigger value!");
|
||||
ASSERT(0);
|
||||
sprintf(cause,"Internal error: got FDEV_TRIGGER without trigger value!");
|
||||
goto end;
|
||||
} );
|
||||
p = data;
|
||||
tv = *p;
|
||||
free(p);
|
||||
CHECK_FCT_DO( fd_event_trig_call_cb(tv), goto end );
|
||||
}
|
||||
break;
|
||||
|
||||
case FDEV_TERMINATE_INT:
|
||||
sprintf(cause,"Internal error: got FDEV_TERMINATE_INT!");
|
||||
|
||||
goto end;
|
||||
|
||||
default:
|
||||
TRACE_DEBUG(INFO, "Unexpected event in the main event queue (%d), ignored.", code);
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
core_shutdown();
|
||||
if(1)
|
||||
{
|
||||
FILE *fp=NULL;
|
||||
|
||||
fp = fopen("fd_cause.txt","w");
|
||||
if(fp)
|
||||
{
|
||||
fprintf(fp,"%s\r\n",cause);
|
||||
fclose(fp);
|
||||
}
|
||||
exit(12);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*********************************/
|
||||
/* Public interfaces */
|
||||
|
||||
/* Initialize the libfdcore internals. This also initializes libfdproto */
|
||||
int fd_core_initialize(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (core_state_get() != CORE_NOT_INIT) {
|
||||
fprintf(stderr, "fd_core_initialize() called more than once!\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Initialize the library -- must come first since it initializes the debug facility */
|
||||
ret = fd_libproto_init();
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Unable to initialize libfdproto: %s\n", strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Name this thread */
|
||||
fd_log_threadname("Main");
|
||||
|
||||
LOG_N("libfdproto '%s' initialized.", fd_libproto_version);
|
||||
|
||||
/* Initialize gcrypt and gnutls */
|
||||
#ifndef GNUTLS_VERSION_210
|
||||
GNUTLS_TRACE( (void) gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread) );
|
||||
GNUTLS_TRACE( (void) gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0) );
|
||||
#endif /* GNUTLS_VERSION_210 */
|
||||
CHECK_GNUTLS_DO( gnutls_global_init(), return EINVAL );
|
||||
if ( ! gnutls_check_version(GNUTLS_VERSION) ) {
|
||||
TRACE_ERROR( "The GNUTLS library is too old; found '%s', need '" GNUTLS_VERSION "'", gnutls_check_version(NULL));
|
||||
return EINVAL;
|
||||
} else {
|
||||
#ifdef GNUTLS_VERSION_210
|
||||
TRACE_DEBUG(INFO, "libgnutls '%s' initialized.", gnutls_check_version(NULL) );
|
||||
#else /* GNUTLS_VERSION_210 */
|
||||
TRACE_DEBUG(INFO, "libgnutls '%s', libgcrypt '%s', initialized.", gnutls_check_version(NULL), gcry_check_version(NULL) );
|
||||
#endif /* GNUTLS_VERSION_210 */
|
||||
}
|
||||
|
||||
/* Initialize the config with default values */
|
||||
memset(&g_conf, 0, sizeof(struct fd_config));
|
||||
fd_g_config = &g_conf;
|
||||
CHECK_FCT( fd_conf_init() );
|
||||
|
||||
/* Add definitions of the base protocol */
|
||||
CHECK_FCT( fd_dict_base_protocol(fd_g_config->cnf_dict) );
|
||||
|
||||
/* Initialize some modules */
|
||||
CHECK_FCT( fd_hooks_init() );
|
||||
CHECK_FCT( fd_queues_init() );
|
||||
CHECK_FCT( fd_sess_start() );
|
||||
CHECK_FCT( fd_p_expi_init() );
|
||||
|
||||
core_state_set(CORE_LIBS_INIT);
|
||||
|
||||
LOG_N("libfdcore '%s' initialized.", fd_core_version);
|
||||
|
||||
|
||||
/* Next thing is to parse the config, leave this for a different function */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static pthread_mutex_t core_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* Parse the freeDiameter.conf configuration file, load the extensions */
|
||||
static int fd_core_parseconf_int(const char * conffile)
|
||||
{
|
||||
char * buf = NULL, *b;
|
||||
size_t len = 0, offset=0;
|
||||
|
||||
|
||||
TRACE_ENTRY("%p", conffile);
|
||||
|
||||
/* Conf file */
|
||||
if (conffile)
|
||||
fd_g_config->cnf_file = conffile; /* otherwise, we use the default name */
|
||||
|
||||
CHECK_FCT( fd_conf_parse() );
|
||||
|
||||
/* The following module use data from the configuration */
|
||||
CHECK_FCT( fd_rtdisp_init() );
|
||||
|
||||
/* Now, load all dynamic extensions */
|
||||
CHECK_FCT( fd_ext_load() );
|
||||
|
||||
/* Display configuration */
|
||||
b = fd_conf_dump(&buf, &len, NULL);
|
||||
LOG_SPLIT(FD_LOG_NOTICE, NULL, b ?: "<Error during configuration dump...>", NULL);
|
||||
|
||||
/* Display extensions status */
|
||||
b = fd_ext_dump(&buf, &len, NULL);
|
||||
LOG_SPLIT(FD_LOG_NOTICE, "Loaded extensions: ", b?:"<Error during extensions dump...>", NULL);
|
||||
|
||||
/* Display registered triggers for FDEV_TRIGGER */
|
||||
b = fd_event_trig_dump(&buf, &len, &offset);
|
||||
if (!b || offset) {
|
||||
LOG_N("%s", b ?: "Error during triggers dump...");
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
/* Since some extensions might have modified the definitions from the dict_base_protocol, we only load the objects now */
|
||||
CHECK_FCT( fd_msg_init() );
|
||||
|
||||
/* Ok, ready for next step */
|
||||
core_state_set(CORE_CONF_READY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fd_core_parseconf(const char * conffile)
|
||||
{
|
||||
int ret;
|
||||
CHECK_POSIX( pthread_mutex_lock(&core_lock) );
|
||||
ret = fd_core_parseconf_int(conffile);
|
||||
CHECK_POSIX( pthread_mutex_unlock(&core_lock) );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* For threads that would need to wait complete start of the framework (ex: in extensions) */
|
||||
int fd_core_waitstartcomplete(void)
|
||||
{
|
||||
TRACE_ENTRY("");
|
||||
|
||||
return core_state_wait(CORE_RUNNING);
|
||||
}
|
||||
|
||||
/*static void free_key(gpointer data)
|
||||
{
|
||||
//printf("We free key: %s /n", data);
|
||||
free(data);
|
||||
}*/
|
||||
|
||||
/* Start the server & client threads */
|
||||
static int fd_core_start_int(void)
|
||||
{
|
||||
/* create hash: session id===>port id */
|
||||
g_sess_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
|
||||
|
||||
/* Start server threads */
|
||||
CHECK_FCT( fd_servers_start() );
|
||||
|
||||
/* Start the peer state machines */
|
||||
CHECK_FCT( fd_psm_start() );
|
||||
|
||||
/* Start the core runner thread that handles main events (until shutdown) */
|
||||
CHECK_POSIX( pthread_create(&core_runner, NULL, core_runner_thread, NULL) );
|
||||
|
||||
/* Unlock threads waiting into fd_core_waitstartcomplete */
|
||||
core_state_set(CORE_RUNNING);
|
||||
|
||||
/* Ok, everything is running now... */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fd_core_start(void)
|
||||
{
|
||||
int ret;
|
||||
CHECK_POSIX( pthread_mutex_lock(&core_lock) );
|
||||
ret = fd_core_start_int();
|
||||
CHECK_POSIX( pthread_mutex_unlock(&core_lock) );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialize shutdown of the framework. This is not blocking. */
|
||||
int fd_core_shutdown(void)
|
||||
{
|
||||
enum core_state cur_state = core_state_get();
|
||||
|
||||
LOG_F("Initiating freeDiameter shutdown sequence (%d)", cur_state);
|
||||
|
||||
if (cur_state < CORE_RUNNING) {
|
||||
/* Calling application must make sure the initialization is not ongoing in a separate thread... */
|
||||
if (pthread_mutex_lock(&core_lock) != 0) {
|
||||
/* This function must not be called asynchronously from fd_core_parseconf / fd_core_start ! Please review your main app design */
|
||||
ASSERT(0);
|
||||
return EINVAL;
|
||||
}
|
||||
core_shutdown();
|
||||
core_state_set(CORE_TERM);
|
||||
pthread_mutex_unlock(&core_lock);
|
||||
} else if (cur_state == CORE_RUNNING) {
|
||||
core_state_set(CORE_SHUTDOWN);
|
||||
CHECK_FCT( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE_INT, 0, NULL) );
|
||||
}
|
||||
|
||||
/* Other case, the framework is already shutting down */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Wait for the shutdown to be complete -- this must be called after fd_core_shutdown to reclaim some resources. */
|
||||
int fd_core_wait_shutdown_complete(void)
|
||||
{
|
||||
enum core_state cur_state = core_state_get();
|
||||
void * th_ret = NULL;
|
||||
|
||||
CHECK_FCT(core_state_wait(CORE_SHUTDOWN));
|
||||
|
||||
if (cur_state == CORE_TERM)
|
||||
return 0;
|
||||
|
||||
/* Just wait for core_runner_thread to complete and return gracefully */
|
||||
CHECK_POSIX(pthread_join(core_runner, &th_ret));
|
||||
|
||||
core_state_set(CORE_TERM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
3355
plat/diameter/libfdcore/dict_base_proto.c
Normal file
3355
plat/diameter/libfdcore/dict_base_proto.c
Normal file
File diff suppressed because it is too large
Load Diff
271
plat/diameter/libfdcore/endpoints.c
Normal file
271
plat/diameter/libfdcore/endpoints.c
Normal file
@@ -0,0 +1,271 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
|
||||
/* Add an endpoint information in a list */
|
||||
int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, uint32_t flags )
|
||||
{
|
||||
struct fd_endpoint * ep;
|
||||
struct fd_list * li;
|
||||
union {
|
||||
sSA * sa;
|
||||
sSA4 *sin;
|
||||
sSA6 *sin6;
|
||||
} ptr;
|
||||
in_port_t * port;
|
||||
int cmp = -1;
|
||||
|
||||
TRACE_ENTRY("%p %p %u %x", list, sa, sl, flags);
|
||||
CHECK_PARAMS( list && sa && (sl <= sizeof(sSS)) );
|
||||
|
||||
if (list->next == NULL) {
|
||||
/* the list is not initialized yet, do it */
|
||||
fd_list_init(list, NULL);
|
||||
}
|
||||
|
||||
ptr.sa = sa;
|
||||
|
||||
/* Filter out a bunch of invalid addresses */
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
if (! (flags & EP_ACCEPTALL)) {
|
||||
if (IN_IS_ADDR_UNSPECIFIED(&ptr.sin->sin_addr)
|
||||
|| IN_IS_ADDR_LOOPBACK(&ptr.sin->sin_addr)
|
||||
/* the next one filters both EXPERIMENTAL, BADCLASS and MULTICAST. */
|
||||
|| ((ntohl(ptr.sin->sin_addr.s_addr) & 0xe0000000) == 0xe0000000)
|
||||
|| (ptr.sin->sin_addr.s_addr == INADDR_BROADCAST)) {
|
||||
LOG_A(" DEBUG:fd_ep_add_merge Address was ignored, not added.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
port = &ptr.sin->sin_port;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
if (! (flags & EP_ACCEPTALL)) {
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&ptr.sin6->sin6_addr)
|
||||
|| IN6_IS_ADDR_LOOPBACK(&ptr.sin6->sin6_addr)
|
||||
|| IN6_IS_ADDR_MULTICAST(&ptr.sin6->sin6_addr)
|
||||
|| IN6_IS_ADDR_LINKLOCAL(&ptr.sin6->sin6_addr)
|
||||
|| IN6_IS_ADDR_SITELOCAL(&ptr.sin6->sin6_addr)) {
|
||||
LOG_A(" DEBUG:fd_ep_add_merge Address was ignored, not added.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
port = &ptr.sin6->sin6_port;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_A(" DEBUG:fd_ep_add_merge Address family was unknown, not added.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* remove the ACCEPTALL flag */
|
||||
flags &= ~EP_ACCEPTALL;
|
||||
|
||||
/* Search place in the list */
|
||||
for (li = list->next; li != list; li = li->next) {
|
||||
ep = (struct fd_endpoint *)li;
|
||||
in_port_t * ep_port;
|
||||
|
||||
/* First, compare the address family */
|
||||
if (ep->sa.sa_family < sa->sa_family)
|
||||
continue;
|
||||
if (ep->sa.sa_family > sa->sa_family)
|
||||
break;
|
||||
|
||||
/* Then compare the address field */
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
cmp = memcmp(&ep->sin.sin_addr, &ptr.sin->sin_addr, sizeof(struct in_addr));
|
||||
ep_port = &ep->sin.sin_port;
|
||||
break;
|
||||
case AF_INET6:
|
||||
cmp = memcmp(&ep->sin6.sin6_addr, &ptr.sin6->sin6_addr, sizeof(struct in6_addr));
|
||||
ep_port = &ep->sin6.sin6_port;
|
||||
break;
|
||||
default:
|
||||
ASSERT( 0 ); /* we got a different value previously in this same function */
|
||||
}
|
||||
if (cmp < 0)
|
||||
continue;
|
||||
if (cmp > 0)
|
||||
break;
|
||||
|
||||
/* Finally compare the port, only if not 0 */
|
||||
if (*port == 0)
|
||||
break;
|
||||
if (*ep_port == 0) {
|
||||
/* save the port information in the list, and break */
|
||||
*ep_port = *port;
|
||||
break;
|
||||
}
|
||||
if (*ep_port < *port) {
|
||||
cmp = -1;
|
||||
continue;
|
||||
}
|
||||
if (*ep_port > *port)
|
||||
cmp = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmp) {
|
||||
/* new item to be added */
|
||||
CHECK_MALLOC( ep = malloc(sizeof(struct fd_endpoint)) );
|
||||
memset(ep, 0, sizeof(struct fd_endpoint));
|
||||
fd_list_init(&ep->chain, NULL);
|
||||
memcpy(&ep->ss, sa, sl);
|
||||
|
||||
/* Insert in the list */
|
||||
fd_list_insert_before(li, &ep->chain);
|
||||
}
|
||||
|
||||
/* Merge the flags */
|
||||
ep->flags |= flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Delete endpoints that do not have a matching flag from a list (0: delete all endpoints) */
|
||||
int fd_ep_filter( struct fd_list * list, uint32_t flags )
|
||||
{
|
||||
struct fd_list * li;
|
||||
|
||||
TRACE_ENTRY("%p %x", list, flags);
|
||||
CHECK_PARAMS(list);
|
||||
|
||||
for (li = list->next; li != list; li = li->next) {
|
||||
struct fd_endpoint * ep = (struct fd_endpoint *)li;
|
||||
|
||||
if (! (ep->flags & flags)) {
|
||||
li = li->prev;
|
||||
fd_list_unlink(&ep->chain);
|
||||
free(ep);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Keep only endpoints of the same family as af */
|
||||
int fd_ep_filter_family( struct fd_list * list, int af )
|
||||
{
|
||||
struct fd_list * li;
|
||||
|
||||
TRACE_ENTRY("%p %d", list, af);
|
||||
CHECK_PARAMS(list);
|
||||
|
||||
for (li = list->next; li != list; li = li->next) {
|
||||
struct fd_endpoint * ep = (struct fd_endpoint *)li;
|
||||
|
||||
if (ep->sa.sa_family != af) {
|
||||
li = li->prev;
|
||||
fd_list_unlink(&ep->chain);
|
||||
free(ep);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reset the given flag(s) from all items in the list */
|
||||
int fd_ep_clearflags( struct fd_list * list, uint32_t flags )
|
||||
{
|
||||
struct fd_list * li;
|
||||
|
||||
TRACE_ENTRY("%p %x", list, flags);
|
||||
CHECK_PARAMS(list);
|
||||
|
||||
for (li = list->next; li != list; li = li->next) {
|
||||
struct fd_endpoint * ep = (struct fd_endpoint *)li;
|
||||
ep->flags &= ~flags;
|
||||
if (ep->flags == 0) {
|
||||
li = li->prev;
|
||||
fd_list_unlink(&ep->chain);
|
||||
free(ep);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump_one, int preamble, struct fd_endpoint * ep )
|
||||
{
|
||||
FD_DUMP_HANDLE_OFFSET();
|
||||
|
||||
if (preamble) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{ep}(@%p): ", ep), return NULL);
|
||||
}
|
||||
|
||||
if (!ep) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
|
||||
return *buf;
|
||||
}
|
||||
|
||||
CHECK_MALLOC_DO( fd_sa_dump( FD_DUMP_STD_PARAMS, &ep->sa, NI_NUMERICHOST | NI_NUMERICSERV ), return NULL);
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{%s%s%s%s%s}",
|
||||
(ep->flags & EP_FL_CONF) ? "C" : "-",
|
||||
(ep->flags & EP_FL_DISC) ? "D" : "-",
|
||||
(ep->flags & EP_FL_ADV) ? "A" : "-",
|
||||
(ep->flags & EP_FL_LL) ? "L" : "-",
|
||||
(ep->flags & EP_FL_PRIMARY) ? "P" : "-"), return NULL);
|
||||
return *buf;
|
||||
}
|
||||
|
||||
DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump, int preamble, int indent, struct fd_list * eps )
|
||||
{
|
||||
struct fd_list * li;
|
||||
|
||||
FD_DUMP_HANDLE_OFFSET();
|
||||
|
||||
if (preamble) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*s{eps}(@%p):", indent, "", eps), return NULL);
|
||||
}
|
||||
if (eps) {
|
||||
for (li = eps->next; li != eps; li = li->next) {
|
||||
struct fd_endpoint * ep = (struct fd_endpoint *)li;
|
||||
if (preamble) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n%*s", indent+1, ""), return NULL);
|
||||
} else if (li->prev != eps) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\t"), return NULL);
|
||||
}
|
||||
CHECK_MALLOC_DO( fd_ep_dump_one( FD_DUMP_STD_PARAMS, preamble, ep ), return NULL);
|
||||
}
|
||||
}
|
||||
return *buf;
|
||||
}
|
||||
|
||||
231
plat/diameter/libfdcore/events.c
Normal file
231
plat/diameter/libfdcore/events.c
Normal file
@@ -0,0 +1,231 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
/* Events are a subset of fifo queues, with a known type */
|
||||
|
||||
int fd_event_send(struct fifo *queue, int code, size_t datasz, void * data)
|
||||
{
|
||||
struct fd_event * ev;
|
||||
CHECK_MALLOC( ev = malloc(sizeof(struct fd_event)) );
|
||||
ev->code = code;
|
||||
ev->size = datasz;
|
||||
ev->data = data;
|
||||
CHECK_FCT( fd_fifo_post(queue, &ev) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fd_event_get(struct fifo *queue, int *code, size_t *datasz, void ** data)
|
||||
{
|
||||
struct fd_event * ev;
|
||||
CHECK_FCT( fd_fifo_get(queue, &ev) );
|
||||
if (code)
|
||||
*code = ev->code;
|
||||
if (datasz)
|
||||
*datasz = ev->size;
|
||||
if (data)
|
||||
*data = ev->data;
|
||||
free(ev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fd_event_timedget(struct fifo *queue, struct timespec * timeout, int timeoutcode, int *code, size_t *datasz, void ** data)
|
||||
{
|
||||
struct fd_event * ev;
|
||||
int ret = 0;
|
||||
ret = fd_fifo_timedget(queue, &ev, timeout);
|
||||
if (ret == ETIMEDOUT) {
|
||||
if (code)
|
||||
*code = timeoutcode;
|
||||
if (datasz)
|
||||
*datasz = 0;
|
||||
if (data)
|
||||
*data = NULL;
|
||||
} else {
|
||||
CHECK_FCT( ret );
|
||||
if (code)
|
||||
*code = ev->code;
|
||||
if (datasz)
|
||||
*datasz = ev->size;
|
||||
if (data)
|
||||
*data = ev->data;
|
||||
free(ev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fd_event_destroy(struct fifo **queue, void (*free_cb)(void * data))
|
||||
{
|
||||
struct fd_event * ev;
|
||||
/* Purge all events, and free the associated data if any */
|
||||
while (fd_fifo_tryget( *queue, &ev ) == 0) {
|
||||
(*free_cb)(ev->data);
|
||||
free(ev);
|
||||
}
|
||||
CHECK_FCT_DO( fd_fifo_del(queue), /* continue */ );
|
||||
return ;
|
||||
}
|
||||
|
||||
const char * fd_ev_str(int event)
|
||||
{
|
||||
switch (event) {
|
||||
#define case_str( _val )\
|
||||
case _val : return #_val
|
||||
case_str(FDEV_TERMINATE_INT);
|
||||
case_str(FDEV_TRIGGER);
|
||||
|
||||
default:
|
||||
TRACE_DEBUG(FULL, "Unknown event : %d", event);
|
||||
return "Unknown event";
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
/* Trigged events */
|
||||
/* This allows extensions to register for / send triggers to other extensions */
|
||||
/* It is used for example for users interactions (through signals or ...) */
|
||||
|
||||
/* Because the number of triggers is not expected to grow, we use a simple ordered chained list */
|
||||
static pthread_rwlock_t trig_rwl = PTHREAD_RWLOCK_INITIALIZER;
|
||||
static struct fd_list trig_list = FD_LIST_INITIALIZER(trig_list); /* The list of triggers ordered by trigger value */
|
||||
struct trig_item {
|
||||
struct fd_list chain;
|
||||
int trig_value;
|
||||
const char * trig_module;
|
||||
void (*cb)(void);
|
||||
};
|
||||
|
||||
/* Add a new entry in the trigger list */
|
||||
int fd_event_trig_regcb(int trigger_val, const char * module, void (*cb)(void))
|
||||
{
|
||||
struct trig_item * ti;
|
||||
struct fd_list * li;
|
||||
|
||||
TRACE_ENTRY("%d %p %p", trigger_val, module, cb);
|
||||
CHECK_PARAMS( trigger_val && cb );
|
||||
|
||||
/* Create a new trig_item */
|
||||
CHECK_MALLOC( ti = malloc(sizeof(struct trig_item)) );
|
||||
memset(ti, 0, sizeof(struct trig_item));
|
||||
fd_list_init(&ti->chain, ti);
|
||||
ti->trig_value = trigger_val;
|
||||
ti->trig_module = module;
|
||||
ti->cb = cb;
|
||||
|
||||
/* Now insert in the list */
|
||||
CHECK_POSIX( pthread_rwlock_wrlock(&trig_rwl) );
|
||||
|
||||
for (li = trig_list.next; li != &trig_list; li = li->next) {
|
||||
struct trig_item *t = li->o;
|
||||
if (t->trig_value >= trigger_val)
|
||||
break;
|
||||
}
|
||||
|
||||
fd_list_insert_before(li, &ti->chain);
|
||||
|
||||
CHECK_POSIX( pthread_rwlock_unlock(&trig_rwl) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECLARE_FD_DUMP_PROTOTYPE(fd_event_trig_dump)
|
||||
{
|
||||
struct fd_list * li;
|
||||
FD_DUMP_HANDLE_OFFSET();
|
||||
|
||||
CHECK_POSIX_DO( pthread_rwlock_rdlock(&trig_rwl), );
|
||||
|
||||
for (li = trig_list.next; li != &trig_list; li = li->next) {
|
||||
struct trig_item *t = li->o;
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{signal:%d}'%s'->%p ", t->trig_value, t->trig_module, t->cb), break);
|
||||
}
|
||||
|
||||
CHECK_POSIX_DO( pthread_rwlock_unlock(&trig_rwl), );
|
||||
return *buf;
|
||||
}
|
||||
|
||||
static void *call_cb_detached(void * arg)
|
||||
{
|
||||
void (*cb)(void) = arg;
|
||||
fd_log_threadname("Trig'd callback thread");
|
||||
TRACE_ENTRY("%p", arg);
|
||||
(*cb)();
|
||||
TRACE_DEBUG(ANNOYING, "Callback %p completed", cb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fd_event_trig_call_cb(int trigger_val)
|
||||
{
|
||||
struct fd_list * li;
|
||||
pthread_attr_t detached;
|
||||
pthread_t th;
|
||||
|
||||
CHECK_POSIX( pthread_attr_init(&detached) );
|
||||
CHECK_POSIX( pthread_attr_setdetachstate(&detached, PTHREAD_CREATE_DETACHED) );
|
||||
|
||||
CHECK_POSIX( pthread_rwlock_rdlock(&trig_rwl) );
|
||||
|
||||
for (li = trig_list.next; li != &trig_list; li = li->next) {
|
||||
struct trig_item *t = li->o;
|
||||
if (t->trig_value == trigger_val) {
|
||||
TRACE_DEBUG(FULL, "Trigger %d: Calling %p in %s", t->trig_value, t->cb, t->trig_module);
|
||||
CHECK_POSIX_DO( pthread_create( &th, &detached, call_cb_detached, t->cb ), break );
|
||||
}
|
||||
if (t->trig_value > trigger_val)
|
||||
break;
|
||||
}
|
||||
|
||||
CHECK_POSIX( pthread_rwlock_unlock(&trig_rwl) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fd_event_trig_fini(void) {
|
||||
|
||||
TRACE_ENTRY("");
|
||||
|
||||
CHECK_POSIX( pthread_rwlock_wrlock(&trig_rwl) );
|
||||
|
||||
while (!FD_IS_LIST_EMPTY(&trig_list)) {
|
||||
struct fd_list * li = trig_list.next;
|
||||
fd_list_unlink(li);
|
||||
free(li);
|
||||
}
|
||||
|
||||
CHECK_POSIX( pthread_rwlock_unlock(&trig_rwl) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
293
plat/diameter/libfdcore/extensions.c
Normal file
293
plat/diameter/libfdcore/extensions.c
Normal file
@@ -0,0 +1,293 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
#include <dlfcn.h> /* We may use libtool's <ltdl.h> later for better portability.... */
|
||||
#include <libgen.h> /* for "basename" */
|
||||
|
||||
/* 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() */
|
||||
const char **depends; /* names of the other extensions this one depends on (if provided) */
|
||||
char *ext_name; /* points to the extension name, either inside depends, or basename(filename) */
|
||||
int free_ext_name; /* must be freed if it was malloc'd */
|
||||
void (*fini)(void); /* optional address of the fd_ext_fini callback */
|
||||
};
|
||||
|
||||
/* list of extensions */
|
||||
static struct fd_list ext_list = FD_LIST_INITIALIZER(ext_list);
|
||||
|
||||
/* Add new extension */
|
||||
int fd_ext_add( char * filename, char * conffile )
|
||||
{
|
||||
struct fd_ext_info * new;
|
||||
|
||||
TRACE_ENTRY("%p %p", filename, 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;
|
||||
}
|
||||
|
||||
/* Dump the list */
|
||||
DECLARE_FD_DUMP_PROTOTYPE(fd_ext_dump)
|
||||
{
|
||||
struct fd_list * li;
|
||||
FD_DUMP_HANDLE_OFFSET();
|
||||
|
||||
if (FD_IS_LIST_EMPTY(&ext_list)) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "-none-"), return NULL);
|
||||
} else {
|
||||
for (li = ext_list.next; li != &ext_list; li = li->next)
|
||||
{
|
||||
struct fd_ext_info * ext = (struct fd_ext_info *)li;
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'[%s], %sloaded%s",
|
||||
ext->filename,
|
||||
ext->conffile?:"(no config file)",
|
||||
ext->handler ? "" : "not ", (li->next == &ext_list) ? "":"\n"), return NULL);
|
||||
}
|
||||
}
|
||||
return *buf;
|
||||
}
|
||||
|
||||
/* Check the dependencies. The object must have been dlopened already. */
|
||||
#if 0
|
||||
static int check_dependencies(struct fd_ext_info * ext)
|
||||
{
|
||||
int i = 1;
|
||||
TRACE_ENTRY( "%p", ext );
|
||||
|
||||
/* Attempt to resolve the dependency array */
|
||||
ext->depends = dlsym( ext->handler, "fd_ext_depends" );
|
||||
if (!ext->depends) {
|
||||
/* Duplicate the filename */
|
||||
char * tmp = strdup(ext->filename);
|
||||
ext->ext_name = strdup(basename(tmp));
|
||||
free(tmp);
|
||||
ext->free_ext_name = 1;
|
||||
TRACE_DEBUG(FULL, "Old extension's [%s] API: missing dependencies (ignored)", ext->ext_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ext->ext_name = (char *)ext->depends[0];
|
||||
|
||||
TRACE_DEBUG(FULL, "Checking dependencies for '%s'...", ext->ext_name);
|
||||
|
||||
while (ext->depends[i]) {
|
||||
struct fd_list * li;
|
||||
for (li = ext_list.next; li != &ext->chain; li = li->next)
|
||||
{
|
||||
struct fd_ext_info * e = (struct fd_ext_info *)li;
|
||||
if (!strcasecmp(e->ext_name, ext->depends[i])) {
|
||||
/* the dependency was already loaded */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (li == &ext->chain) {
|
||||
/* the dependency was not found */
|
||||
LOG_F("Error: extension [%s] depends on [%s] which was not loaded first. Please fix your configuration file.",
|
||||
ext->ext_name, ext->depends[i]);
|
||||
return ESRCH;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
/* All dependencies resolved successfully */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Load all extensions in the list */
|
||||
/* fj added 2016/06/22 */
|
||||
#if 1
|
||||
extern int fd_ext_init(int major, int minor, char * conffile);
|
||||
int fd_ext_load()
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
fd_ext_init(FD_PROJECT_VERSION_MAJOR, FD_PROJECT_VERSION_MINOR, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
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;
|
||||
LOG_D( "Loading : %s", ext->filename);
|
||||
|
||||
/* Load the extension */
|
||||
#ifndef DEBUG
|
||||
ext->handler = dlopen(ext->filename, RTLD_LAZY | RTLD_GLOBAL);
|
||||
#else /* DEBUG */
|
||||
/* We resolve symbols immediatly so it's easier to find problems in ABI */
|
||||
ext->handler = dlopen(ext->filename, RTLD_NOW | RTLD_GLOBAL);
|
||||
#endif /* DEBUG */
|
||||
if (ext->handler == NULL) {
|
||||
/* An error occured */
|
||||
LOG_F("Loading of extension %s failed: %s", ext->filename, dlerror());
|
||||
ext->handler = dlopen(ext->filename, RTLD_LAZY | RTLD_GLOBAL);
|
||||
if (ext->handler) {
|
||||
if (!check_dependencies(ext)) {
|
||||
LOG_F("In addition, not all declared dependencies are satisfied (Internal Error!)");
|
||||
}
|
||||
}
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Check if declared dependencies are satisfied. */
|
||||
CHECK_FCT( check_dependencies(ext) );
|
||||
|
||||
/* 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_ERROR("Unable to resolve symbol 'fd_ext_init' for extension %s: %s", 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_ERROR("Extension %s returned an error during initialization: %s", ext->filename, strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Proceed to the next extension */
|
||||
}
|
||||
|
||||
LOG_N("All extensions loaded.");
|
||||
|
||||
/* We have finished. */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Now unload the extensions and free the memory */
|
||||
/* fj added 2016/06/22 */
|
||||
#if 1
|
||||
extern void fd_ext_fini(void);
|
||||
int fd_ext_term( void )
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
fd_ext_fini();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
int fd_ext_term( 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->ext_name ?: ext->filename);
|
||||
(*ext->fini)();
|
||||
}
|
||||
|
||||
#ifndef SKIP_DLCLOSE
|
||||
/* Now unload the extension */
|
||||
if (ext->handler) {
|
||||
TRACE_DEBUG (FULL, "Unloading %s", ext->ext_name ?: ext->filename);
|
||||
if ( dlclose(ext->handler) != 0 ) {
|
||||
TRACE_DEBUG (INFO, "Unloading [%s] failed : %s", ext->ext_name ?: ext->filename, dlerror());
|
||||
}
|
||||
}
|
||||
#endif /* SKIP_DLCLOSE */
|
||||
|
||||
/* Free the object and continue */
|
||||
if (ext->free_ext_name)
|
||||
free(ext->ext_name);
|
||||
free(ext->filename);
|
||||
free(ext->conffile);
|
||||
free(ext);
|
||||
}
|
||||
|
||||
/* We always return 0 since we would not handle an error anyway... */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
375
plat/diameter/libfdcore/fdcore-internal.h
Normal file
375
plat/diameter/libfdcore/fdcore-internal.h
Normal file
@@ -0,0 +1,375 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/* This file contains the definitions for internal use in the freeDiameter core library */
|
||||
|
||||
#ifndef _FDCORE_INTERNAL_H
|
||||
#define _FDCORE_INTERNAL_H
|
||||
|
||||
#include "freeDiameter-host.h"
|
||||
#include "libfdcore.h"
|
||||
|
||||
#ifdef DISABLE_SCTP
|
||||
#undef IPPROTO_SCTP
|
||||
#define IPPROTO_SCTP (2 = 4) /* some compilation error to spot the references */
|
||||
#endif /* DISABLE_SCTP */
|
||||
|
||||
#ifndef HAVE_AI_ADDRCONFIG
|
||||
#define AI_ADDRCONFIG 0 /* ignore this flag at the moment */
|
||||
#endif /* HAVE_AI_ADDRCONFIG */
|
||||
|
||||
/* Timeout for establishing a connection */
|
||||
#ifndef CNX_TIMEOUT
|
||||
#define CNX_TIMEOUT 10 /* in seconds */
|
||||
#endif /* CNX_TIMEOUT */
|
||||
|
||||
/* Timeout for receiving a CER after incoming connection is established */
|
||||
#ifndef INCNX_TIMEOUT
|
||||
#define INCNX_TIMEOUT 20 /* in seconds */
|
||||
#endif /* INCNX_TIMEOUT */
|
||||
|
||||
/* Timeout for receiving a CEA after CER is sent */
|
||||
#ifndef CEA_TIMEOUT
|
||||
#define CEA_TIMEOUT 20 /* in seconds */
|
||||
#endif /* CEA_TIMEOUT */
|
||||
|
||||
/* The timeout value to wait for answer to a DPR */
|
||||
#ifndef DPR_TIMEOUT
|
||||
#define DPR_TIMEOUT 15 /* in seconds */
|
||||
#endif /* DPR_TIMEOUT */
|
||||
|
||||
/* Delay where the connection is maintained opened to allow exchanging remaining pending answers after DPR/DPA */
|
||||
#ifndef GRACE_TIMEOUT
|
||||
#define GRACE_TIMEOUT 1 /* in seconds */
|
||||
#endif /* GRACE_TIMEOUT */
|
||||
|
||||
/* The Vendor-Id to advertise in CER/CEA */
|
||||
#ifndef MY_VENDOR_ID
|
||||
#define MY_VENDOR_ID 0 /* Reserved value to tell it must be ignored */
|
||||
#endif /* MY_VENDOR_ID */
|
||||
|
||||
|
||||
|
||||
/* Configuration */
|
||||
int fd_conf_init();
|
||||
int fd_conf_deinit();
|
||||
int fd_conf_parse();
|
||||
int fddparse(struct fd_config * conf); /* yacc generated */
|
||||
int fd_conf_stream_to_gnutls_datum(FILE * pemfile, gnutls_datum_t *out);
|
||||
|
||||
|
||||
/* Extensions */
|
||||
int fd_ext_add( char * filename, char * conffile );
|
||||
int fd_ext_load();
|
||||
int fd_ext_term(void);
|
||||
|
||||
/* Messages */
|
||||
int fd_msg_init(void);
|
||||
extern struct dict_object * fd_dict_avp_OSI; /* Origin-State-Id */
|
||||
extern struct dict_object * fd_dict_cmd_CER; /* Capabilities-Exchange-Request */
|
||||
extern struct dict_object * fd_dict_cmd_DWR; /* Device-Watchdog-Request */
|
||||
extern struct dict_object * fd_dict_avp_DC; /* Disconnect-Cause */
|
||||
extern struct dict_object * fd_dict_cmd_DPR; /* Disconnect-Peer-Request */
|
||||
|
||||
/* Global message queues */
|
||||
extern struct fifo * fd_g_incoming; /* all messages received from other peers, except local messages (CER, ...) */
|
||||
extern struct fifo * fd_g_outgoing; /* messages to be sent to other peers on the network following routing procedure */
|
||||
extern struct fifo * fd_g_local; /* messages to be handled to local extensions */
|
||||
/* Message queues */
|
||||
int fd_queues_init(void);
|
||||
int fd_queues_fini(struct fifo ** queue);
|
||||
|
||||
/* Trigged events */
|
||||
int fd_event_trig_call_cb(int trigger_val);
|
||||
int fd_event_trig_fini(void);
|
||||
|
||||
/* Create all the dictionary objects defined in the Diameter base RFC. */
|
||||
int fd_dict_base_protocol(struct dictionary * dict);
|
||||
|
||||
/* Routing */
|
||||
int fd_rtdisp_init(void);
|
||||
int fd_rtdisp_cleanstop(void);
|
||||
int fd_rtdisp_fini(void);
|
||||
int fd_rtdisp_cleanup(void);
|
||||
|
||||
/* Sentinel for the sent requests list */
|
||||
struct sr_list {
|
||||
struct fd_list srs; /* requests ordered by hop-by-hop id */
|
||||
struct fd_list exp; /* requests that have a timeout set, ordered by timeout */
|
||||
long cnt; /* number of requests in the srs list */
|
||||
long cnt_lost; /* number of requests that have not been answered in time.
|
||||
It is decremented when an unexpected answer is received, so this may not be accurate. */
|
||||
pthread_mutex_t mtx; /* mutex to protect these lists */
|
||||
pthread_cond_t cnd; /* cond var used by the thread that handles timeouts */
|
||||
pthread_t thr; /* the thread that handles timeouts (expirecb called in separate forked threads) */
|
||||
};
|
||||
|
||||
/* Peers */
|
||||
struct fd_peer { /* The "real" definition of the peer structure */
|
||||
|
||||
/* The public data */
|
||||
struct peer_hdr p_hdr;
|
||||
|
||||
/* Eye catcher, EYEC_PEER */
|
||||
int p_eyec;
|
||||
#define EYEC_PEER 0x373C9336
|
||||
|
||||
/* Origin of this peer object, for debug */
|
||||
char *p_dbgorig;
|
||||
|
||||
/* State of the peer, and its lock */
|
||||
enum peer_state p_state;
|
||||
pthread_mutex_t p_state_mtx;
|
||||
|
||||
/* Chaining in peers sublists */
|
||||
struct fd_list p_actives; /* list of peers in the STATE_OPEN state -- used by routing */
|
||||
struct fd_list p_expiry; /* list of expiring peers, ordered by their timeout value */
|
||||
struct timespec p_exp_timer; /* Timestamp where the peer will expire; updated each time activity is seen on the peer (except DW) */
|
||||
|
||||
/* Some flags influencing the peer state machine */
|
||||
struct {
|
||||
unsigned pf_responder : 1; /* The peer has been created to handle incoming connection */
|
||||
unsigned pf_delete : 1; /* Destroy the peer when the connection is terminated */
|
||||
unsigned pf_localterm : 1; /* If the latest DPR/DPA was initiated from this side */
|
||||
|
||||
unsigned pf_dw_pending : 1; /* A DWR message was sent and not answered yet */
|
||||
|
||||
unsigned pf_cnx_pb : 1; /* The peer was disconnected because of watchdogs; must exchange 3 watchdogs before putting back to normal */
|
||||
unsigned pf_reopen_cnt : 2; /* remaining DW to be exchanged after re-established connection */
|
||||
|
||||
} p_flags;
|
||||
|
||||
/* The events queue, peer state machine thread, timer for states timeouts */
|
||||
struct fifo *p_events; /* The mutex of this FIFO list protects also the state and timer information */
|
||||
pthread_t p_psm;
|
||||
struct timespec p_psm_timer;
|
||||
|
||||
/* Outgoing message queue, and thread managing sending the messages */
|
||||
struct fifo *p_tosend;
|
||||
pthread_t p_outthr;
|
||||
|
||||
/* The next hop-by-hop id value for the link, only read & modified by p_outthr */
|
||||
uint32_t p_hbh;
|
||||
|
||||
/* Sent requests (for fallback), list of struct sentreq ordered by hbh */
|
||||
struct sr_list p_sr;
|
||||
struct fifo *p_tofailover;
|
||||
|
||||
/* Pending received requests not yet answered (count only) */
|
||||
long p_reqin_count; /* We use p_state_mtx to protect this value */
|
||||
|
||||
/* Data for transitional states before the peer is in OPEN state */
|
||||
struct {
|
||||
struct cnxctx * p_receiver; /* Only used in case of election */
|
||||
struct msg * p_cer; /* Only used in case of election */
|
||||
|
||||
pthread_t p_ini_thr; /* Initiator thread for establishing a connection */
|
||||
struct fd_list p_connparams; /* The list of connection attempts, see p_cnx.c */
|
||||
};
|
||||
|
||||
/* connection context: socket and related information */
|
||||
struct cnxctx *p_cnxctx;
|
||||
|
||||
/* Callback for peer validation after the handshake */
|
||||
int (*p_cb2)(struct peer_info *);
|
||||
|
||||
/* Callback on initial connection success / failure after the peer was added */
|
||||
void (*p_cb)(struct peer_info *, void *);
|
||||
void *p_cb_data;
|
||||
|
||||
};
|
||||
#define CHECK_PEER( _p ) \
|
||||
(((_p) != NULL) && (((struct fd_peer *)(_p))->p_eyec == EYEC_PEER))
|
||||
|
||||
#define fd_peer_getstate(peer) fd_peer_get_state((struct peer_hdr *)(peer))
|
||||
|
||||
|
||||
/* Events codespace for struct fd_peer->p_events */
|
||||
enum {
|
||||
/* request to terminate this peer : disconnect, requeue all messages */
|
||||
FDEVP_TERMINATE = 1500
|
||||
|
||||
/* A connection object has received a message. (data contains the buffer + padding + struct fd_msg_pmdl) */
|
||||
,FDEVP_CNX_MSG_RECV
|
||||
|
||||
/* A connection object has encountered an error (disconnected). */
|
||||
,FDEVP_CNX_ERROR
|
||||
|
||||
/* Endpoints of a connection have been changed (multihomed SCTP). */
|
||||
,FDEVP_CNX_EP_CHANGE
|
||||
|
||||
/* The connection is being shutdown (SCTP notification). */
|
||||
,FDEVP_CNX_SHUTDOWN
|
||||
|
||||
/* A new connection (with a CER) has been received */
|
||||
,FDEVP_CNX_INCOMING
|
||||
|
||||
/* A new connection has been established to the remote peer (event data is the cnxctx object) */
|
||||
,FDEVP_CNX_ESTABLISHED
|
||||
|
||||
/* A connection attempt (initiator side) has failed */
|
||||
,FDEVP_CNX_FAILED
|
||||
|
||||
/* The PSM state is expired */
|
||||
,FDEVP_PSM_TIMEOUT
|
||||
|
||||
};
|
||||
#define CHECK_PEVENT( _e ) \
|
||||
(((int)(_e) >= FDEVP_TERMINATE) && ((int)(_e) <= FDEVP_PSM_TIMEOUT))
|
||||
/* The following macro is actually called in p_psm.c -- another solution would be to declare it static inline */
|
||||
#define DECLARE_PEV_STR() \
|
||||
const char * fd_pev_str(int event) \
|
||||
{ \
|
||||
switch (event) { \
|
||||
case_str(FDEVP_TERMINATE); \
|
||||
case_str(FDEVP_CNX_MSG_RECV); \
|
||||
case_str(FDEVP_CNX_ERROR); \
|
||||
case_str(FDEVP_CNX_EP_CHANGE); \
|
||||
case_str(FDEVP_CNX_INCOMING); \
|
||||
case_str(FDEVP_CNX_ESTABLISHED); \
|
||||
case_str(FDEVP_CNX_FAILED); \
|
||||
case_str(FDEVP_PSM_TIMEOUT); \
|
||||
} \
|
||||
TRACE_DEBUG(FULL, "Unknown event : %d", event); \
|
||||
return "Unknown event"; \
|
||||
}
|
||||
const char * fd_pev_str(int event);
|
||||
|
||||
/* The data structure for FDEVP_CNX_INCOMING event */
|
||||
struct cnx_incoming {
|
||||
struct msg * cer; /* the CER message received on this connection */
|
||||
struct cnxctx * cnx; /* The connection context */
|
||||
int validate; /* The peer is new, it must be validated (by an extension) or error CEA to be sent */
|
||||
};
|
||||
|
||||
/* Functions */
|
||||
int fd_peer_fini();
|
||||
int fd_peer_alloc(struct fd_peer ** ptr);
|
||||
int fd_peer_free(struct fd_peer ** ptr);
|
||||
int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx );
|
||||
/* fd_peer_add declared in freeDiameter.h */
|
||||
int fd_peer_validate( struct fd_peer * peer );
|
||||
void fd_peer_failover_msg(struct fd_peer * peer);
|
||||
|
||||
/* Peer expiry */
|
||||
int fd_p_expi_init(void);
|
||||
int fd_p_expi_fini(void);
|
||||
int fd_p_expi_update(struct fd_peer * peer );
|
||||
|
||||
/* Peer state machine */
|
||||
int fd_psm_start();
|
||||
int fd_psm_begin(struct fd_peer * peer );
|
||||
int fd_psm_terminate(struct fd_peer * peer, char * reason );
|
||||
void fd_psm_abord(struct fd_peer * peer );
|
||||
void fd_psm_next_timeout(struct fd_peer * peer, int add_random, int delay);
|
||||
int fd_psm_change_state(struct fd_peer * peer, int new_state);
|
||||
void fd_psm_cleanup(struct fd_peer * peer, int terminate);
|
||||
|
||||
/* Peer out */
|
||||
int fd_out_send(struct msg ** msg, struct cnxctx * cnx, struct fd_peer * peer, int update_reqin_cnt);
|
||||
int fd_out_start(struct fd_peer * peer);
|
||||
int fd_out_stop(struct fd_peer * peer);
|
||||
|
||||
/* Initiating connections */
|
||||
int fd_p_cnx_init(struct fd_peer * peer);
|
||||
void fd_p_cnx_abort(struct fd_peer * peer, int cleanup_all);
|
||||
|
||||
/* Peer sent requests cache */
|
||||
int fd_p_sr_store(struct sr_list * srlist, struct msg **req, uint32_t *hbhloc, uint32_t hbh_restore);
|
||||
int fd_p_sr_fetch(struct sr_list * srlist, uint32_t hbh, struct msg **req);
|
||||
int fd_p_sr_start(struct sr_list * srlist);
|
||||
int fd_p_sr_stop(struct sr_list * srlist);
|
||||
void fd_p_sr_failover(struct sr_list * srlist);
|
||||
|
||||
/* Local Link messages (CER/CEA, DWR/DWA, DPR/DPA) */
|
||||
int fd_p_ce_msgrcv(struct msg ** msg, int req, struct fd_peer * peer);
|
||||
int fd_p_ce_handle_newCER(struct msg ** msg, struct fd_peer * peer, struct cnxctx ** cnx, int valid);
|
||||
int fd_p_ce_handle_newcnx(struct fd_peer * peer, struct cnxctx * initiator);
|
||||
int fd_p_ce_process_receiver(struct fd_peer * peer);
|
||||
void fd_p_ce_clear_cnx(struct fd_peer * peer, struct cnxctx ** cnx_kept);
|
||||
int fd_p_dw_handle(struct msg ** msg, int req, struct fd_peer * peer);
|
||||
int fd_p_dw_timeout(struct fd_peer * peer);
|
||||
int fd_p_dw_reopen(struct fd_peer * peer);
|
||||
int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer);
|
||||
int fd_p_dp_initiate(struct fd_peer * peer, char * reason);
|
||||
int fd_p_dp_newdelay(struct fd_peer * peer);
|
||||
|
||||
/* Active peers -- routing process should only ever take the read lock, the write lock is managed by PSMs */
|
||||
extern struct fd_list fd_g_activ_peers;
|
||||
extern pthread_rwlock_t fd_g_activ_peers_rw; /* protect the list */
|
||||
|
||||
|
||||
/* Server sockets */
|
||||
int fd_servers_start();
|
||||
int fd_servers_stop();
|
||||
|
||||
/* Connection contexts -- there are also definitions in cnxctx.h for the relevant files */
|
||||
struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint * ep);
|
||||
struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list);
|
||||
int fd_cnx_serv_listen(struct cnxctx * conn);
|
||||
struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv);
|
||||
struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa, socklen_t addrlen);
|
||||
struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list);
|
||||
int fd_cnx_start_clear(struct cnxctx * conn, int loop);
|
||||
void fd_cnx_sethostname(struct cnxctx * conn, DiamId_t hn);
|
||||
int fd_cnx_proto_info(struct cnxctx * conn, char * buf, size_t len);
|
||||
#define ALGO_HANDSHAKE_DEFAULT 0 /* TLS for TCP, DTLS for SCTP */
|
||||
#define ALGO_HANDSHAKE_3436 1 /* For TLS for SCTP also */
|
||||
int fd_cnx_handshake(struct cnxctx * conn, int mode, int algo, char * priority, void * alt_creds);
|
||||
char * fd_cnx_getid(struct cnxctx * conn);
|
||||
int fd_cnx_getproto(struct cnxctx * conn);
|
||||
int fd_cnx_getTLS(struct cnxctx * conn);
|
||||
int fd_cnx_is_unordered_delivery_supported(struct cnxctx * conn);
|
||||
int fd_cnx_unordered_delivery(struct cnxctx * conn, int is_allowed);
|
||||
int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size);
|
||||
int fd_cnx_get_local_eps(struct fd_list * list);
|
||||
int fd_cnx_getremoteeps(struct cnxctx * conn, struct fd_list * eps);
|
||||
char * fd_cnx_getremoteid(struct cnxctx * conn);
|
||||
int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len);
|
||||
int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo); /* send FDEVP_CNX_MSG_RECV event to the fifo list */
|
||||
int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len);
|
||||
void fd_cnx_destroy(struct cnxctx * conn);
|
||||
#ifdef GNUTLS_VERSION_300
|
||||
int fd_tls_verify_credentials_2(gnutls_session_t session);
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
|
||||
/* Internal calls of the hook mechanism */
|
||||
void fd_hook_call(enum fd_hook_type type, struct msg * msg, struct fd_peer * peer, void * other, struct fd_msg_pmdl * pmdl);
|
||||
void fd_hook_associate(struct msg * msg, struct fd_msg_pmdl * pmdl);
|
||||
int fd_hooks_init(void);
|
||||
size_t fd_msg_pmdl_sizewithoverhead(size_t datalen);
|
||||
struct fd_msg_pmdl * fd_msg_pmdl_get_inbuf(uint8_t * buf, size_t datalen);
|
||||
|
||||
#endif /* _FDCORE_INTERNAL_H */
|
||||
285
plat/diameter/libfdcore/fdd.l
Normal file
285
plat/diameter/libfdcore/fdd.l
Normal file
@@ -0,0 +1,285 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/* 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 "fdcore-internal.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; \
|
||||
fd_log_debug( \
|
||||
"(%d:%d-%d:%d) matched rule %d, length=%d, txt='%s'", \
|
||||
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
|
||||
|
||||
/* Additional for files inclusion */
|
||||
#include <glob.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_NESTED_CONF_FILES 5
|
||||
|
||||
struct nested_conffiles_t {
|
||||
YY_BUFFER_STATE parent_level_state;
|
||||
glob_t filelist;
|
||||
int current_file;
|
||||
} nested_conffiles[MAX_NESTED_CONF_FILES];
|
||||
|
||||
int current_nested_level = 0;
|
||||
|
||||
int globerrfct(const char *epath, int eerrno)
|
||||
{
|
||||
TRACE_ERROR("Failed to scan %s: %s", epath, strerror(eerrno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%option bison-bridge bison-locations
|
||||
%option noyywrap
|
||||
%option nounput
|
||||
|
||||
%x in_include
|
||||
|
||||
/* 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 */
|
||||
|
||||
|
||||
include BEGIN(in_include);
|
||||
/* Following an "include" keyword */
|
||||
<in_include>{
|
||||
{qstring} { /* Name of the file to include. This is directly sent to glob. */
|
||||
int globerror=0;
|
||||
char * buf = strdup(yytext+1);
|
||||
if (buf[yyleng-2] != '"')
|
||||
{
|
||||
TRACE_ERROR("Unterminated string: %s", yytext);
|
||||
return LEX_ERROR;
|
||||
}
|
||||
buf[yyleng-2] = '\0';
|
||||
|
||||
if (current_nested_level >= MAX_NESTED_CONF_FILES)
|
||||
{
|
||||
TRACE_ERROR("Too many recursion levels in configuration files includes");
|
||||
return LEX_ERROR;
|
||||
}
|
||||
|
||||
/* glob the include */
|
||||
globerror = glob(buf, GLOB_ERR, globerrfct, &nested_conffiles[current_nested_level].filelist);
|
||||
|
||||
if (globerror == GLOB_NOSPACE)
|
||||
{
|
||||
TRACE_ERROR("Not enough memory to parse include directive.");
|
||||
return LEX_ERROR;
|
||||
}
|
||||
if (globerror == GLOB_ABORTED)
|
||||
{
|
||||
TRACE_ERROR("An error was encountered in include directive.");
|
||||
return LEX_ERROR;
|
||||
}
|
||||
if (globerror == GLOB_NOMATCH)
|
||||
{
|
||||
globfree(&nested_conffiles[current_nested_level].filelist);
|
||||
goto nomatch;
|
||||
}
|
||||
if (globerror)
|
||||
{
|
||||
TRACE_ERROR("Unexpected error in glob (%d).", globerror);
|
||||
return LEX_ERROR;
|
||||
}
|
||||
|
||||
/* We have a list of files to include. */
|
||||
|
||||
/* save the current buffer for returning when this include has been parsed */
|
||||
nested_conffiles[current_nested_level].parent_level_state = YY_CURRENT_BUFFER;
|
||||
|
||||
/* Start with the first match */
|
||||
nested_conffiles[current_nested_level].current_file = 0;
|
||||
|
||||
yyin = fopen( nested_conffiles[current_nested_level].filelist.gl_pathv[0], "r" );
|
||||
|
||||
if ( ! yyin )
|
||||
{
|
||||
TRACE_ERROR("Error in %s: %s", nested_conffiles[current_nested_level].filelist.gl_pathv[0], strerror(errno));
|
||||
return LEX_ERROR;
|
||||
}
|
||||
|
||||
yy_switch_to_buffer(yy_create_buffer( yyin, YY_BUF_SIZE ));
|
||||
|
||||
/* In case of recursive includes */
|
||||
current_nested_level++;
|
||||
|
||||
nomatch:
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
}
|
||||
|
||||
<<EOF>> {
|
||||
if (current_nested_level == 0)
|
||||
{
|
||||
/* We are at the end of parsing */
|
||||
yyterminate();
|
||||
}
|
||||
|
||||
/* Otherwise we are doing an include statement */
|
||||
--current_nested_level;
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER);
|
||||
|
||||
/* Go to next file, if any */
|
||||
nested_conffiles[current_nested_level].current_file++;
|
||||
if ( nested_conffiles[current_nested_level].filelist.gl_pathv[nested_conffiles[current_nested_level].current_file] == NULL )
|
||||
{
|
||||
/* We have finished with this list of includes */
|
||||
globfree(&nested_conffiles[current_nested_level].filelist);
|
||||
yy_switch_to_buffer(nested_conffiles[current_nested_level].parent_level_state);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Proceed to next included file */
|
||||
yyin = fopen( nested_conffiles[current_nested_level].filelist.gl_pathv[nested_conffiles[current_nested_level].current_file], "r" );
|
||||
|
||||
if ( ! yyin )
|
||||
{
|
||||
TRACE_ERROR("Error in %s: %s", nested_conffiles[current_nested_level].filelist.gl_pathv[nested_conffiles[current_nested_level].current_file], strerror(errno));
|
||||
return LEX_ERROR;
|
||||
}
|
||||
|
||||
yy_switch_to_buffer(yy_create_buffer( yyin, YY_BUF_SIZE ));
|
||||
|
||||
/* In case of recursive includes */
|
||||
current_nested_level++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
{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 */
|
||||
TRACE_ERROR("Unable to convert the value '%s' to a valid number: %s", 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:"Identity") { return IDENTITY; }
|
||||
(?i:"Realm") { return REALM; }
|
||||
(?i:"Port") { return PORT; }
|
||||
(?i:"SecPort") { return SECPORT; }
|
||||
/* (?i:"SctpSec3436") { return SEC3436; } */
|
||||
(?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:"AppServThreads") { return APPSERVTHREADS;}
|
||||
(?i:"ListenOn") { return LISTENON; }
|
||||
(?i:"ThreadsPerServer") { return THRPERSRV; }
|
||||
(?i:"TcTimer") { return TCTIMER; }
|
||||
(?i:"TwTimer") { return TWTIMER; }
|
||||
(?i:"NoRelay") { return NORELAY; }
|
||||
(?i:"LoadExtension") { return LOADEXT; }
|
||||
(?i:"ConnectPeer") { return CONNPEER; }
|
||||
(?i:"ConnectTo") { return CONNTO; }
|
||||
(?i:"No_TLS") { return NOTLS; }
|
||||
(?i:"TLS_Cred") { return TLS_CRED; }
|
||||
(?i:"TLS_CA") { return TLS_CA; }
|
||||
(?i:"TLS_CRL") { return TLS_CRL; }
|
||||
(?i:"TLS_Prio") { return TLS_PRIO; }
|
||||
(?i:"TLS_DH_bits") { return TLS_DH_BITS; }
|
||||
(?i:"TLS_DH_file") { return TLS_DH_FILE; }
|
||||
|
||||
|
||||
/* 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 */
|
||||
<*>. {
|
||||
TRACE_ERROR("Unrecognized text on line %d col %d: '%s'.", yylloc->first_line, yylloc->first_column, yytext);
|
||||
return LEX_ERROR;
|
||||
}
|
||||
|
||||
%%
|
||||
667
plat/diameter/libfdcore/fdd.y
Normal file
667
plat/diameter/libfdcore/fdd.y
Normal file
@@ -0,0 +1,667 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2015, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/* 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 "fdcore-internal.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) {
|
||||
TRACE_ERROR("%s:%d.%d-%d.%d : %s", conf->cnf_file, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s);
|
||||
} else if (ploc->first_column != ploc->last_column) {
|
||||
TRACE_ERROR("%s:%d.%d-%d : %s", conf->cnf_file, ploc->first_line, ploc->first_column, ploc->last_column, s);
|
||||
} else {
|
||||
TRACE_ERROR("%s:%d.%d : %s", conf->cnf_file, ploc->first_line, ploc->first_column, s);
|
||||
}
|
||||
}
|
||||
|
||||
int got_peer_noip = 0;
|
||||
int got_peer_noipv6 = 0;
|
||||
int got_peer_notcp = 0;
|
||||
int got_peer_nosctp = 0;
|
||||
|
||||
struct peer_info fddpi;
|
||||
|
||||
%}
|
||||
|
||||
/* 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 <string> QSTRING
|
||||
%token <integer> INTEGER
|
||||
|
||||
%type <string> extconf
|
||||
|
||||
%token IDENTITY
|
||||
%token REALM
|
||||
%token PORT
|
||||
%token SECPORT
|
||||
%token SEC3436
|
||||
%token NOIP
|
||||
%token NOIP6
|
||||
%token NOTCP
|
||||
%token NOSCTP
|
||||
%token PREFERTCP
|
||||
%token OLDTLS
|
||||
%token NOTLS
|
||||
%token SCTPSTREAMS
|
||||
%token APPSERVTHREADS
|
||||
%token LISTENON
|
||||
%token THRPERSRV
|
||||
%token TCTIMER
|
||||
%token TWTIMER
|
||||
%token NORELAY
|
||||
%token LOADEXT
|
||||
%token CONNPEER
|
||||
%token CONNTO
|
||||
%token TLS_CRED
|
||||
%token TLS_CA
|
||||
%token TLS_CRL
|
||||
%token TLS_PRIO
|
||||
%token TLS_DH_BITS
|
||||
%token TLS_DH_FILE
|
||||
|
||||
|
||||
/* -------------------------------------- */
|
||||
%%
|
||||
|
||||
/* The grammar definition - Sections blocs. */
|
||||
conffile: /* Empty is OK -- for simplicity here, we reject in daemon later */
|
||||
| conffile identity
|
||||
| conffile realm
|
||||
| conffile tctimer
|
||||
| conffile twtimer
|
||||
| conffile port
|
||||
| conffile secport
|
||||
| conffile sec3436
|
||||
| conffile sctpstreams
|
||||
| conffile listenon
|
||||
| conffile thrpersrv
|
||||
| conffile norelay
|
||||
| conffile appservthreads
|
||||
| conffile noip
|
||||
| conffile noip6
|
||||
| conffile notcp
|
||||
| conffile nosctp
|
||||
| conffile prefertcp
|
||||
| conffile oldtls
|
||||
| conffile loadext
|
||||
| conffile connpeer
|
||||
| conffile tls_cred
|
||||
| conffile tls_ca
|
||||
| conffile tls_crl
|
||||
| conffile tls_prio
|
||||
| conffile tls_dh
|
||||
| conffile errors
|
||||
{
|
||||
yyerror(&yylloc, conf, "An error occurred while parsing the configuration file");
|
||||
return EINVAL;
|
||||
}
|
||||
;
|
||||
|
||||
/* Lexical or syntax error */
|
||||
errors: LEX_ERROR
|
||||
| error
|
||||
;
|
||||
|
||||
identity: IDENTITY '=' QSTRING ';'
|
||||
{
|
||||
conf->cnf_diamid = $3;
|
||||
}
|
||||
;
|
||||
|
||||
realm: REALM '=' QSTRING ';'
|
||||
{
|
||||
conf->cnf_diamrlm = $3;
|
||||
}
|
||||
;
|
||||
|
||||
tctimer: TCTIMER '=' INTEGER ';'
|
||||
{
|
||||
CHECK_PARAMS_DO( ($3 > 0),
|
||||
{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
|
||||
conf->cnf_timer_tc = (unsigned int)$3;
|
||||
}
|
||||
;
|
||||
|
||||
twtimer: TWTIMER '=' INTEGER ';'
|
||||
{
|
||||
CHECK_PARAMS_DO( ($3 > 5),
|
||||
{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
|
||||
conf->cnf_timer_tw = (unsigned int)$3;
|
||||
}
|
||||
;
|
||||
|
||||
port: PORT '=' INTEGER ';'
|
||||
{
|
||||
CHECK_PARAMS_DO( ($3 >= 0) && ($3 < 1<<16),
|
||||
{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
|
||||
conf->cnf_port = (uint16_t)$3;
|
||||
}
|
||||
;
|
||||
|
||||
secport: SECPORT '=' INTEGER ';'
|
||||
{
|
||||
CHECK_PARAMS_DO( ($3 >= 0) && ($3 < 1<<16),
|
||||
{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
|
||||
conf->cnf_port_tls = (uint16_t)$3;
|
||||
}
|
||||
;
|
||||
|
||||
sec3436: SEC3436 '=' INTEGER ';'
|
||||
{
|
||||
CHECK_PARAMS_DO( ($3 >= 0) && ($3 < 1<<16),
|
||||
{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
|
||||
conf->cnf_port_3436 = (uint16_t)$3;
|
||||
}
|
||||
;
|
||||
|
||||
sctpstreams: SCTPSTREAMS '=' INTEGER ';'
|
||||
{
|
||||
CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16),
|
||||
{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
|
||||
conf->cnf_sctp_str = (uint16_t)$3;
|
||||
}
|
||||
;
|
||||
|
||||
listenon: LISTENON '=' QSTRING ';'
|
||||
{
|
||||
struct addrinfo hints, *ai;
|
||||
int ret;
|
||||
|
||||
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; }
|
||||
CHECK_FCT_DO( fd_ep_add_merge( &conf->cnf_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF ), YYERROR );
|
||||
freeaddrinfo(ai);
|
||||
free($3);
|
||||
}
|
||||
;
|
||||
|
||||
thrpersrv: THRPERSRV '=' INTEGER ';'
|
||||
{
|
||||
CHECK_PARAMS_DO( ($3 > 0),
|
||||
{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
|
||||
conf->cnf_thr_srv = $3;
|
||||
}
|
||||
;
|
||||
|
||||
norelay: NORELAY ';'
|
||||
{
|
||||
conf->cnf_flags.no_fwd = 1;
|
||||
}
|
||||
;
|
||||
|
||||
appservthreads: APPSERVTHREADS '=' INTEGER ';'
|
||||
{
|
||||
CHECK_PARAMS_DO( ($3 > 0) && ($3 < 256),
|
||||
{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
|
||||
conf->cnf_dispthr = (uint16_t)$3;
|
||||
}
|
||||
;
|
||||
|
||||
noip: NOIP ';'
|
||||
{
|
||||
if (got_peer_noipv6) {
|
||||
yyerror (&yylloc, conf, "No_IP conflicts with a ConnectPeer directive No_IPv6.");
|
||||
YYERROR;
|
||||
}
|
||||
conf->cnf_flags.no_ip4 = 1;
|
||||
}
|
||||
;
|
||||
|
||||
noip6: NOIP6 ';'
|
||||
{
|
||||
if (got_peer_noip) {
|
||||
yyerror (&yylloc, conf, "No_IP conflicts with a ConnectPeer directive No_IP.");
|
||||
YYERROR;
|
||||
}
|
||||
conf->cnf_flags.no_ip6 = 1;
|
||||
}
|
||||
;
|
||||
|
||||
notcp: NOTCP ';'
|
||||
{
|
||||
#ifdef DISABLE_SCTP
|
||||
yyerror (&yylloc, conf, "No_TCP cannot be specified for daemon compiled with DISABLE_SCTP option.");
|
||||
YYERROR;
|
||||
#endif
|
||||
if (conf->cnf_flags.no_sctp)
|
||||
{
|
||||
yyerror (&yylloc, conf, "No_TCP conflicts with No_SCTP directive." );
|
||||
YYERROR;
|
||||
}
|
||||
if (got_peer_nosctp) {
|
||||
yyerror (&yylloc, conf, "No_TCP conflicts with a ConnectPeer directive No_SCTP.");
|
||||
YYERROR;
|
||||
}
|
||||
conf->cnf_flags.no_tcp = 1;
|
||||
}
|
||||
;
|
||||
|
||||
nosctp: NOSCTP ';'
|
||||
{
|
||||
if (conf->cnf_flags.no_tcp)
|
||||
{
|
||||
yyerror (&yylloc, conf, "No_SCTP conflicts with No_TCP directive." );
|
||||
YYERROR;
|
||||
}
|
||||
if (got_peer_notcp) {
|
||||
yyerror (&yylloc, conf, "No_SCTP conflicts with a ConnectPeer directive No_TCP.");
|
||||
YYERROR;
|
||||
}
|
||||
conf->cnf_flags.no_sctp = 1;
|
||||
}
|
||||
;
|
||||
|
||||
prefertcp: PREFERTCP ';'
|
||||
{
|
||||
conf->cnf_flags.pr_tcp = 1;
|
||||
}
|
||||
;
|
||||
|
||||
oldtls: OLDTLS ';'
|
||||
{
|
||||
conf->cnf_flags.tls_alg = 1;
|
||||
}
|
||||
;
|
||||
|
||||
loadext: LOADEXT '=' QSTRING extconf ';'
|
||||
{
|
||||
char * fname;
|
||||
char * cfname;
|
||||
FILE * fd;
|
||||
|
||||
/* Try and open the extension file */
|
||||
fname = $3;
|
||||
fd = fopen(fname, "r");
|
||||
if ((fd == NULL) && (*fname != '/')) {
|
||||
char * bkp = fname;
|
||||
CHECK_MALLOC_DO( fname = malloc( strlen(bkp) + strlen(DEFAULT_EXTENSIONS_PATH) + 2 ),
|
||||
{ yyerror (&yylloc, conf, "Not enough memory"); YYERROR; } );
|
||||
sprintf(fname, DEFAULT_EXTENSIONS_PATH "/%s", bkp);
|
||||
fd = fopen(fname, "r");
|
||||
if (fd == NULL) {
|
||||
free(fname);
|
||||
fname = bkp;
|
||||
} else {
|
||||
free(bkp);
|
||||
}
|
||||
}
|
||||
if (fd != NULL) {
|
||||
fclose(fd);
|
||||
} /* otherwise, LD_LIBRARY_PATH will be tested by dl_open.
|
||||
This should not give any security issue, otherwise we can add an "else fail" here. */
|
||||
|
||||
/* Try and open the configuration file (optional) */
|
||||
cfname = $4;
|
||||
if (cfname) {
|
||||
fd = fopen(cfname, "r");
|
||||
if ((fd == NULL) && (*cfname != '/')) {
|
||||
char * test;
|
||||
CHECK_MALLOC_DO( test = malloc( strlen(cfname) + strlen(DEFAULT_CONF_PATH) + 2 ),
|
||||
{ yyerror (&yylloc, conf, "Not enough memory"); YYERROR; } );
|
||||
sprintf(test, DEFAULT_CONF_PATH "/%s", cfname);
|
||||
fd = fopen(test, "r");
|
||||
if (fd) {
|
||||
free(cfname);
|
||||
cfname=test;
|
||||
} else {
|
||||
/* This is not an error, we allow an extension to wait for something else than a real conf file. */
|
||||
free(test);
|
||||
}
|
||||
}
|
||||
if (fd)
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
CHECK_FCT_DO( fd_ext_add( fname, cfname ),
|
||||
{ yyerror (&yylloc, conf, "Error adding extension"); YYERROR; } );
|
||||
}
|
||||
;
|
||||
|
||||
extconf: /* empty */
|
||||
{
|
||||
$$ = NULL;
|
||||
}
|
||||
| ':' QSTRING
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
connpeer: {
|
||||
memset(&fddpi, 0, sizeof(fddpi));
|
||||
fddpi.config.pic_flags.persist = PI_PRST_ALWAYS;
|
||||
fd_list_init( &fddpi.pi_endpoints, NULL );
|
||||
}
|
||||
CONNPEER '=' QSTRING peerinfo ';'
|
||||
{
|
||||
fddpi.pi_diamid = $4;
|
||||
CHECK_FCT_DO( fd_peer_add ( &fddpi, conf->cnf_file, NULL, NULL ),
|
||||
{ yyerror (&yylloc, conf, "Error adding ConnectPeer information"); YYERROR; } );
|
||||
|
||||
/* Now destroy any content in the structure */
|
||||
free(fddpi.pi_diamid);
|
||||
free(fddpi.config.pic_realm);
|
||||
free(fddpi.config.pic_priority);
|
||||
while (!FD_IS_LIST_EMPTY(&fddpi.pi_endpoints)) {
|
||||
struct fd_list * li = fddpi.pi_endpoints.next;
|
||||
fd_list_unlink(li);
|
||||
free(li);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
peerinfo: /* empty */
|
||||
| '{' peerparams '}'
|
||||
;
|
||||
|
||||
peerparams: /* empty */
|
||||
| peerparams NOIP ';'
|
||||
{
|
||||
if ((conf->cnf_flags.no_ip6) || (fddpi.config.pic_flags.pro3 == PI_P3_IP)) {
|
||||
yyerror (&yylloc, conf, "No_IP conflicts with a No_IPv6 directive.");
|
||||
YYERROR;
|
||||
}
|
||||
got_peer_noip++;
|
||||
fddpi.config.pic_flags.pro3 = PI_P3_IPv6;
|
||||
}
|
||||
| peerparams NOIP6 ';'
|
||||
{
|
||||
if ((conf->cnf_flags.no_ip4) || (fddpi.config.pic_flags.pro3 == PI_P3_IPv6)) {
|
||||
yyerror (&yylloc, conf, "No_IPv6 conflicts with a No_IP directive.");
|
||||
YYERROR;
|
||||
}
|
||||
got_peer_noipv6++;
|
||||
fddpi.config.pic_flags.pro3 = PI_P3_IP;
|
||||
}
|
||||
| peerparams NOTCP ';'
|
||||
{
|
||||
#ifdef DISABLE_SCTP
|
||||
yyerror (&yylloc, conf, "No_TCP cannot be specified in daemon compiled with DISABLE_SCTP option.");
|
||||
YYERROR;
|
||||
#endif
|
||||
if ((conf->cnf_flags.no_sctp) || (fddpi.config.pic_flags.pro4 == PI_P4_TCP)) {
|
||||
yyerror (&yylloc, conf, "No_TCP conflicts with a No_SCTP directive.");
|
||||
YYERROR;
|
||||
}
|
||||
got_peer_notcp++;
|
||||
fddpi.config.pic_flags.pro4 = PI_P4_SCTP;
|
||||
}
|
||||
| peerparams NOSCTP ';'
|
||||
{
|
||||
if ((conf->cnf_flags.no_tcp) || (fddpi.config.pic_flags.pro4 == PI_P4_SCTP)) {
|
||||
yyerror (&yylloc, conf, "No_SCTP conflicts with a No_TCP directive.");
|
||||
YYERROR;
|
||||
}
|
||||
got_peer_nosctp++;
|
||||
fddpi.config.pic_flags.pro4 = PI_P4_TCP;
|
||||
}
|
||||
| peerparams PREFERTCP ';'
|
||||
{
|
||||
fddpi.config.pic_flags.alg = PI_ALGPREF_TCP;
|
||||
}
|
||||
| peerparams OLDTLS ';'
|
||||
{
|
||||
fddpi.config.pic_flags.sec |= PI_SEC_TLS_OLD;
|
||||
}
|
||||
| peerparams NOTLS ';'
|
||||
{
|
||||
fddpi.config.pic_flags.sec |= PI_SEC_NONE;
|
||||
}
|
||||
| peerparams SEC3436 ';'
|
||||
{
|
||||
fddpi.config.pic_flags.sctpsec |= PI_SCTPSEC_3436;
|
||||
}
|
||||
| peerparams REALM '=' QSTRING ';'
|
||||
{
|
||||
fddpi.config.pic_realm = $4;
|
||||
}
|
||||
| peerparams PORT '=' INTEGER ';'
|
||||
{
|
||||
CHECK_PARAMS_DO( ($4 > 0) && ($4 < 1<<16),
|
||||
{ yyerror (&yylloc, conf, "Invalid port value"); YYERROR; } );
|
||||
fddpi.config.pic_port = (uint16_t)$4;
|
||||
}
|
||||
| peerparams TCTIMER '=' INTEGER ';'
|
||||
{
|
||||
fddpi.config.pic_tctimer = $4;
|
||||
}
|
||||
| peerparams TWTIMER '=' INTEGER ';'
|
||||
{
|
||||
fddpi.config.pic_twtimer = $4;
|
||||
}
|
||||
| peerparams TLS_PRIO '=' QSTRING ';'
|
||||
{
|
||||
fddpi.config.pic_priority = $4;
|
||||
}
|
||||
| peerparams CONNTO '=' QSTRING ';'
|
||||
{
|
||||
struct addrinfo hints, *ai;
|
||||
int ret;
|
||||
int disc = 0;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
|
||||
ret = getaddrinfo($4, NULL, &hints, &ai);
|
||||
if (ret == EAI_NONAME) {
|
||||
/* The name was maybe not numeric, try again */
|
||||
disc = EP_FL_DISC;
|
||||
hints.ai_flags &= ~ AI_NUMERICHOST;
|
||||
ret = getaddrinfo($4, NULL, &hints, &ai);
|
||||
}
|
||||
if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }
|
||||
|
||||
CHECK_FCT_DO( fd_ep_add_merge( &fddpi.pi_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF | (disc ?: EP_ACCEPTALL) ), YYERROR );
|
||||
free($4);
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
;
|
||||
|
||||
tls_cred: TLS_CRED '=' QSTRING ',' QSTRING ';'
|
||||
{
|
||||
FILE * fd;
|
||||
fd = fopen($3, "r");
|
||||
if (fd == NULL) {
|
||||
int ret = errno;
|
||||
TRACE_ERROR("Unable to open certificate file %s for reading: %s", $3, strerror(ret));
|
||||
yyerror (&yylloc, conf, "Error on file name");
|
||||
YYERROR;
|
||||
}
|
||||
fclose(fd);
|
||||
fd = fopen($5, "r");
|
||||
if (fd == NULL) {
|
||||
int ret = errno;
|
||||
TRACE_ERROR("Unable to open private key file %s for reading: %s", $5, strerror(ret));
|
||||
yyerror (&yylloc, conf, "Error on file name");
|
||||
YYERROR;
|
||||
}
|
||||
fclose(fd);
|
||||
conf->cnf_sec_data.cert_file = $3;
|
||||
conf->cnf_sec_data.key_file = $5;
|
||||
|
||||
CHECK_GNUTLS_DO( gnutls_certificate_set_x509_key_file(
|
||||
conf->cnf_sec_data.credentials,
|
||||
conf->cnf_sec_data.cert_file,
|
||||
conf->cnf_sec_data.key_file,
|
||||
GNUTLS_X509_FMT_PEM),
|
||||
{ yyerror (&yylloc, conf, "Error opening certificate or private key file."); YYERROR; } );
|
||||
}
|
||||
;
|
||||
|
||||
tls_ca: TLS_CA '=' QSTRING ';'
|
||||
{
|
||||
FILE * fd;
|
||||
fd = fopen($3, "rb");
|
||||
if (fd == NULL) {
|
||||
int ret = errno;
|
||||
TRACE_ERROR("Unable to open CA file %s for reading: %s", $3, strerror(ret));
|
||||
yyerror (&yylloc, conf, "Error on file name");
|
||||
YYERROR;
|
||||
}
|
||||
#ifdef GNUTLS_VERSION_300
|
||||
{
|
||||
/* We import these CA in the trust list */
|
||||
gnutls_x509_crt_t * calist;
|
||||
unsigned int cacount;
|
||||
gnutls_datum_t cafile;
|
||||
|
||||
CHECK_FCT_DO( fd_conf_stream_to_gnutls_datum(fd, &cafile),
|
||||
{ yyerror (&yylloc, conf, "Error reading CA file."); YYERROR; } );
|
||||
|
||||
CHECK_GNUTLS_DO( gnutls_x509_crt_list_import2(&calist, &cacount, &cafile, GNUTLS_X509_FMT_PEM,
|
||||
GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED),
|
||||
{ yyerror (&yylloc, conf, "Error importing CA file."); YYERROR; } );
|
||||
free(cafile.data);
|
||||
|
||||
CHECK_GNUTLS_DO( gnutls_x509_trust_list_add_cas (fd_g_config->cnf_sec_data.trustlist, calist, cacount, 0),
|
||||
{ yyerror (&yylloc, conf, "Error saving CA in trust list."); YYERROR; } );
|
||||
}
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
fclose(fd);
|
||||
conf->cnf_sec_data.ca_file = $3;
|
||||
CHECK_GNUTLS_DO( conf->cnf_sec_data.ca_file_nr += gnutls_certificate_set_x509_trust_file(
|
||||
conf->cnf_sec_data.credentials,
|
||||
conf->cnf_sec_data.ca_file,
|
||||
GNUTLS_X509_FMT_PEM),
|
||||
{ yyerror (&yylloc, conf, "Error setting CA parameters."); YYERROR; } );
|
||||
|
||||
}
|
||||
;
|
||||
|
||||
tls_crl: TLS_CRL '=' QSTRING ';'
|
||||
{
|
||||
FILE * fd;
|
||||
fd = fopen($3, "rb");
|
||||
if (fd == NULL) {
|
||||
int ret = errno;
|
||||
TRACE_ERROR("Unable to open CRL file %s for reading: %s", $3, strerror(ret));
|
||||
yyerror (&yylloc, conf, "Error on file name");
|
||||
YYERROR;
|
||||
}
|
||||
#ifdef GNUTLS_VERSION_300
|
||||
{
|
||||
/* We import these CRL in the trust list */
|
||||
gnutls_x509_crl_t * crllist;
|
||||
unsigned int crlcount;
|
||||
gnutls_datum_t crlfile;
|
||||
|
||||
CHECK_FCT_DO( fd_conf_stream_to_gnutls_datum(fd, &crlfile),
|
||||
{ yyerror (&yylloc, conf, "Error reading CRL file."); YYERROR; } );
|
||||
|
||||
CHECK_GNUTLS_DO( gnutls_x509_crl_list_import2(&crllist, &crlcount, &crlfile, GNUTLS_X509_FMT_PEM, 0),
|
||||
{ yyerror (&yylloc, conf, "Error importing CRL file."); YYERROR; } );
|
||||
free(crlfile.data);
|
||||
|
||||
CHECK_GNUTLS_DO( gnutls_x509_trust_list_add_crls (fd_g_config->cnf_sec_data.trustlist, crllist, crlcount,
|
||||
GNUTLS_TL_VERIFY_CRL,
|
||||
0),
|
||||
{ yyerror (&yylloc, conf, "Error importing CRL in trust list."); YYERROR; } );
|
||||
}
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
fclose(fd);
|
||||
conf->cnf_sec_data.crl_file = $3;
|
||||
CHECK_GNUTLS_DO( gnutls_certificate_set_x509_crl_file(
|
||||
conf->cnf_sec_data.credentials,
|
||||
conf->cnf_sec_data.crl_file,
|
||||
GNUTLS_X509_FMT_PEM),
|
||||
{ yyerror (&yylloc, conf, "Error setting CRL parameters."); YYERROR; } );
|
||||
}
|
||||
;
|
||||
|
||||
tls_prio: TLS_PRIO '=' QSTRING ';'
|
||||
{
|
||||
const char * err_pos = NULL;
|
||||
conf->cnf_sec_data.prio_string = $3;
|
||||
CHECK_GNUTLS_DO( gnutls_priority_init(
|
||||
&conf->cnf_sec_data.prio_cache,
|
||||
conf->cnf_sec_data.prio_string,
|
||||
&err_pos),
|
||||
{ yyerror (&yylloc, conf, "Error setting Priority parameter.");
|
||||
TRACE_ERROR("Error at position : %s", err_pos);
|
||||
YYERROR; } );
|
||||
}
|
||||
;
|
||||
|
||||
tls_dh: TLS_DH_BITS '=' INTEGER ';'
|
||||
{
|
||||
conf->cnf_sec_data.dh_bits = $3;
|
||||
}
|
||||
| TLS_DH_FILE '=' QSTRING ';'
|
||||
{
|
||||
FILE * fd;
|
||||
free(conf->cnf_sec_data.dh_file);
|
||||
conf->cnf_sec_data.dh_file = $3;
|
||||
fd = fopen($3, "r");
|
||||
if (fd == NULL) {
|
||||
int ret = errno;
|
||||
TRACE_ERROR("Unable to open DH file %s for reading: %s", $3, strerror(ret));
|
||||
yyerror (&yylloc, conf, "Error on file name");
|
||||
YYERROR;
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
;
|
||||
79
plat/diameter/libfdcore/fifo_stats.c
Normal file
79
plat/diameter/libfdcore/fifo_stats.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
/* See include/freeDiameter/libfdcore.h for more information */
|
||||
int fd_stat_getstats(enum fd_stat_type stat, struct peer_hdr * peer,
|
||||
int * current_count, int * limit_count, int * highest_count, long long * total_count,
|
||||
struct timespec * total, struct timespec * blocking, struct timespec * last)
|
||||
{
|
||||
struct fd_peer * p = (struct fd_peer *)peer;
|
||||
TRACE_ENTRY( "%d %p %p %p %p %p %p %p %p", stat, peer, current_count, limit_count, highest_count, total_count, total, blocking, last);
|
||||
|
||||
switch (stat) {
|
||||
case STAT_G_LOCAL: {
|
||||
CHECK_FCT( fd_fifo_getstats(fd_g_local, current_count, limit_count, highest_count, total_count, total, blocking, last) );
|
||||
}
|
||||
break;
|
||||
|
||||
case STAT_G_INCOMING: {
|
||||
CHECK_FCT( fd_fifo_getstats(fd_g_incoming, current_count, limit_count, highest_count, total_count, total, blocking, last) );
|
||||
}
|
||||
break;
|
||||
|
||||
case STAT_G_OUTGOING: {
|
||||
CHECK_FCT( fd_fifo_getstats(fd_g_outgoing, current_count, limit_count, highest_count, total_count, total, blocking, last) );
|
||||
}
|
||||
break;
|
||||
|
||||
case STAT_P_PSM: {
|
||||
CHECK_PARAMS( CHECK_PEER( peer ) );
|
||||
CHECK_FCT( fd_fifo_getstats(p->p_events, current_count, limit_count, highest_count, total_count, total, blocking, last) );
|
||||
}
|
||||
break;
|
||||
|
||||
case STAT_P_TOSEND: {
|
||||
CHECK_PARAMS( CHECK_PEER( peer ) );
|
||||
CHECK_FCT( fd_fifo_getstats(p->p_tosend, current_count, limit_count, highest_count, total_count, total, blocking, last) );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
106
plat/diameter/libfdcore/freeDiameter-host.h
Normal file
106
plat/diameter/libfdcore/freeDiameter-host.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/* Configuration from compile-time */
|
||||
#ifndef FD_IS_CONFIG
|
||||
#define FD_IS_CONFIG
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* #undef HAVE_NTOHLL */
|
||||
#define HAVE_MALLOC_H
|
||||
/* #undef HAVE_SIGNALENT_H */
|
||||
#define HAVE_AI_ADDRCONFIG
|
||||
#define HAVE_CLOCK_GETTIME
|
||||
#define HAVE_STRNDUP
|
||||
#define HAVE_PTHREAD_BAR
|
||||
|
||||
/* #undef HOST_BIG_ENDIAN */
|
||||
|
||||
/* #undef DISABLE_SCTP */
|
||||
/* #undef DEBUG_SCTP */
|
||||
/* #undef DEBUG_WITH_META */
|
||||
/* #undef SCTP_USE_MAPPED_ADDRESSES */
|
||||
#define SCTP_CONNECTX_4_ARGS
|
||||
/* #undef SKIP_DLCLOSE */
|
||||
/* #undef DIAMID_IDNA_IGNORE */
|
||||
/* #undef DIAMID_IDNA_REJECT */
|
||||
/* #undef DISABLE_PEER_EXPIRY */
|
||||
/* #undef WORKAROUND_ACCEPT_INVALID_VSAI */
|
||||
#define GNUTLS_VERSION_210
|
||||
#define GNUTLS_VERSION_212
|
||||
/* #undef GNUTLS_VERSION_300 */
|
||||
/* #undef GNUTLS_VERSION_310 */
|
||||
|
||||
/* #undef ERRORS_ON_TODO */
|
||||
/* #undef DEBUG */
|
||||
|
||||
#define FD_PROJECT_BINARY "freeDiameterd"
|
||||
#define FD_PROJECT_NAME "freeDiameter"
|
||||
#define FD_PROJECT_VERSION_MAJOR 1
|
||||
#ifndef FD_PROJECT_VERSION_MAJOR
|
||||
# define FD_PROJECT_VERSION_MAJOR 0
|
||||
#endif /*FD_PROJECT_VERSION_MAJOR*/
|
||||
#define FD_PROJECT_VERSION_MINOR 2
|
||||
#ifndef FD_PROJECT_VERSION_MINOR
|
||||
# define FD_PROJECT_VERSION_MINOR 0
|
||||
#endif /*FD_PROJECT_VERSION_MINOR*/
|
||||
#define FD_PROJECT_VERSION_REV 1
|
||||
#ifndef FD_PROJECT_VERSION_REV
|
||||
# define FD_PROJECT_VERSION_REV 0
|
||||
#endif /*FD_PROJECT_VERSION_REV*/
|
||||
#define FD_PROJECT_VERSION_API 6
|
||||
#ifndef FD_PROJECT_VERSION_API
|
||||
# define FD_PROJECT_VERSION_API 0
|
||||
#endif /*FD_PROJECT_VERSION_API*/
|
||||
#define FD_PROJECT_COPYRIGHT "Copyright (c) 2008-2015, WIDE Project (www.wide.ad.jp) and NICT (www.nict.go.jp)"
|
||||
|
||||
#define DEFAULT_CONF_PATH "DEFAULT_CONF_PATH"
|
||||
#define DEFAULT_EXTENSIONS_PATH "CMAKE_INSTALL_PREFIX/INSTALL_EXTENSIONS_SUFFIX"
|
||||
|
||||
#ifndef FD_DEFAULT_CONF_FILENAME
|
||||
#define FD_DEFAULT_CONF_FILENAME "freeDiameter.conf"
|
||||
#endif /* FD_DEFAULT_CONF_FILENAME */
|
||||
|
||||
/* Maximum number of hooks handlers that can be registered. Make this compilation option if needed */
|
||||
#define FD_HOOK_HANDLE_LIMIT 5
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FD_IS_CONFIG */
|
||||
454
plat/diameter/libfdcore/hooks.c
Normal file
454
plat/diameter/libfdcore/hooks.c
Normal file
@@ -0,0 +1,454 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
/* Structures for the fd_hook_data_hdl management */
|
||||
static struct fd_hook_data_hdl {
|
||||
size_t pmd_size;
|
||||
void (*pmd_init_cb)(struct fd_hook_permsgdata *);
|
||||
void (*pmd_fini_cb)(struct fd_hook_permsgdata *);
|
||||
} HDH_array[FD_HOOK_HANDLE_LIMIT];
|
||||
static int max_index = 0;
|
||||
static pthread_mutex_t HDH_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* The structure linked from the msg structure list */
|
||||
struct pmd_list_item {
|
||||
struct fd_list chain; /* this list is ordered by hdl */
|
||||
struct fd_hook_data_hdl * hdl;
|
||||
struct fd_hook_permsgdata { } pmd; /* this data belongs to the extension; we only know the size of it */
|
||||
};
|
||||
|
||||
#define sizeof_pmd(hdl) (((size_t)&((struct pmd_list_item *)0)->pmd) + hdl->pmd_size)
|
||||
|
||||
/* Now a hook registered by an extension */
|
||||
struct fd_hook_hdl {
|
||||
struct fd_list chain[HOOK_LAST+1];
|
||||
void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata);
|
||||
void *regdata;
|
||||
struct fd_hook_data_hdl *data_hdl;
|
||||
};
|
||||
|
||||
/* Array of those hooks */
|
||||
struct {
|
||||
struct fd_list sentinel;
|
||||
pthread_rwlock_t rwlock;
|
||||
} HS_array[HOOK_LAST+1];
|
||||
|
||||
/* Initialize the array of sentinels for the hooks */
|
||||
int fd_hooks_init(void)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i <= HOOK_LAST; i++) {
|
||||
fd_list_init(&HS_array[i].sentinel, NULL);
|
||||
CHECK_POSIX( pthread_rwlock_init(&HS_array[i].rwlock, NULL) );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get a slot in the array */
|
||||
int fd_hook_data_register(
|
||||
size_t permsgdata_size,
|
||||
void (*permsgdata_init_cb) (struct fd_hook_permsgdata *),
|
||||
void (*permsgdata_fini_cb) (struct fd_hook_permsgdata *),
|
||||
struct fd_hook_data_hdl **new_handle)
|
||||
{
|
||||
int ret = ENOSPC, idx;
|
||||
TRACE_ENTRY("%zd %p %p %p", permsgdata_size, permsgdata_init_cb, permsgdata_fini_cb, new_handle);
|
||||
|
||||
CHECK_PARAMS( permsgdata_size && new_handle );
|
||||
|
||||
CHECK_POSIX( pthread_mutex_lock(&HDH_lock) );
|
||||
if (max_index < FD_HOOK_HANDLE_LIMIT) {
|
||||
idx = max_index++;
|
||||
ret = 0;
|
||||
}
|
||||
CHECK_POSIX( pthread_mutex_unlock(&HDH_lock) );
|
||||
|
||||
if (ret == 0) {
|
||||
HDH_array[idx].pmd_size = permsgdata_size;
|
||||
HDH_array[idx].pmd_init_cb = permsgdata_init_cb;
|
||||
HDH_array[idx].pmd_fini_cb = permsgdata_fini_cb;
|
||||
*new_handle = &HDH_array[idx];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Register a new hook callback */
|
||||
int fd_hook_register ( uint32_t type_mask,
|
||||
void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata),
|
||||
void *regdata,
|
||||
struct fd_hook_data_hdl *data_hdl,
|
||||
struct fd_hook_hdl ** handler )
|
||||
{
|
||||
struct fd_hook_hdl * newhdl = NULL;
|
||||
int i;
|
||||
|
||||
TRACE_ENTRY("%x %p %p %p %p", type_mask, fd_hook_cb, regdata, data_hdl, handler);
|
||||
|
||||
CHECK_PARAMS( fd_hook_cb && handler );
|
||||
|
||||
CHECK_MALLOC( newhdl = malloc(sizeof(struct fd_hook_hdl)) );
|
||||
memset(newhdl, 0, sizeof(struct fd_hook_hdl));
|
||||
|
||||
newhdl->fd_hook_cb = fd_hook_cb;
|
||||
newhdl->regdata = regdata;
|
||||
newhdl->data_hdl = data_hdl;
|
||||
|
||||
for (i=0; i <= HOOK_LAST; i++) {
|
||||
fd_list_init(&newhdl->chain[i], newhdl);
|
||||
if (type_mask & (1<<i)) {
|
||||
CHECK_POSIX( pthread_rwlock_wrlock(&HS_array[i].rwlock) );
|
||||
fd_list_insert_before( &HS_array[i].sentinel, &newhdl->chain[i]);
|
||||
CHECK_POSIX( pthread_rwlock_unlock(&HS_array[i].rwlock) );
|
||||
}
|
||||
}
|
||||
|
||||
*handler = newhdl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* free this hook callback */
|
||||
int fd_hook_unregister( struct fd_hook_hdl * handler )
|
||||
{
|
||||
int i;
|
||||
TRACE_ENTRY("%p", handler);
|
||||
CHECK_PARAMS( handler );
|
||||
|
||||
for (i=0; i <= HOOK_LAST; i++) {
|
||||
if ( ! FD_IS_LIST_EMPTY(&handler->chain[i])) {
|
||||
CHECK_POSIX( pthread_rwlock_wrlock(&HS_array[i].rwlock) );
|
||||
fd_list_unlink(&handler->chain[i]);
|
||||
CHECK_POSIX( pthread_rwlock_unlock(&HS_array[i].rwlock) );
|
||||
}
|
||||
}
|
||||
|
||||
free(handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* callback for the libfdproto to free the data associated with a message */
|
||||
static void pmdl_free(struct fd_msg_pmdl *pmdl)
|
||||
{
|
||||
/* destroy all the items in the list */
|
||||
while (!FD_IS_LIST_EMPTY(&pmdl->sentinel)) {
|
||||
struct pmd_list_item * li = (struct pmd_list_item *)(pmdl->sentinel.next);
|
||||
if (li->hdl->pmd_fini_cb) {
|
||||
(*li->hdl->pmd_fini_cb)(&li->pmd);
|
||||
}
|
||||
fd_list_unlink(&li->chain);
|
||||
free(li);
|
||||
}
|
||||
CHECK_POSIX_DO( pthread_mutex_destroy(&pmdl->lock), );
|
||||
pmdl->sentinel.o = NULL;
|
||||
}
|
||||
|
||||
/* Save the list of pmd into the message structure, as well as the callback to free this list */
|
||||
void fd_hook_associate(struct msg * msg, struct fd_msg_pmdl * pmdl)
|
||||
{
|
||||
struct fd_msg_pmdl * in_msg;
|
||||
|
||||
CHECK_PARAMS_DO( msg && pmdl, return );
|
||||
in_msg = fd_msg_pmdl_get(msg);
|
||||
ASSERT(in_msg && (in_msg->sentinel.o == NULL)); /* error / already initialized ??? */
|
||||
in_msg->sentinel.o = pmdl_free;
|
||||
/* Now move all items from the pmdl pointer into the initialized list */
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&pmdl->lock), );
|
||||
fd_list_move_end(&in_msg->sentinel, &pmdl->sentinel);
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&pmdl->lock), );
|
||||
pmdl_free(pmdl);
|
||||
/* We're done */
|
||||
}
|
||||
|
||||
/* Return the location of the permsgdata area corresponding to this handle, after eventually having created it. Return NULL in case of failure */
|
||||
static struct fd_hook_permsgdata * get_or_create_pmd(struct fd_msg_pmdl *pmdl, struct fd_hook_hdl * h)
|
||||
{
|
||||
struct fd_hook_permsgdata * ret = NULL;
|
||||
struct fd_list * li;
|
||||
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&pmdl->lock), );
|
||||
|
||||
if (pmdl->sentinel.o == NULL) {
|
||||
pmdl->sentinel.o = pmdl_free;
|
||||
}
|
||||
|
||||
/* Search in the list for an item with the same handle. The list is ordered by this handle */
|
||||
for (li=pmdl->sentinel.next; li != &pmdl->sentinel; li = li->next) {
|
||||
struct pmd_list_item * pli = (struct pmd_list_item *) li;
|
||||
if (pli->hdl == h->data_hdl)
|
||||
ret = &pli->pmd;
|
||||
if (pli->hdl >= h->data_hdl)
|
||||
break;
|
||||
}
|
||||
if (!ret) {
|
||||
/* we need to create a new one and insert before li */
|
||||
struct pmd_list_item * pli;
|
||||
CHECK_MALLOC_DO( pli = malloc(sizeof_pmd(h->data_hdl)), );
|
||||
if (pli) {
|
||||
memset(pli, 0, sizeof_pmd(h->data_hdl));
|
||||
fd_list_init(&pli->chain, pli);
|
||||
pli->hdl = h->data_hdl;
|
||||
ret = &pli->pmd;
|
||||
if (h->data_hdl->pmd_init_cb) {
|
||||
(*h->data_hdl->pmd_init_cb)(ret);
|
||||
}
|
||||
fd_list_insert_before(li, &pli->chain);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&pmdl->lock), );
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct fd_hook_permsgdata * fd_hook_get_request_pmd(struct fd_hook_data_hdl *data_hdl, struct msg * answer)
|
||||
{
|
||||
struct msg * qry;
|
||||
struct fd_msg_pmdl *pmdl;
|
||||
struct fd_hook_permsgdata * ret = NULL;
|
||||
struct fd_list * li;
|
||||
|
||||
CHECK_FCT_DO( fd_msg_answ_getq(answer, &qry), return NULL );
|
||||
if (!qry)
|
||||
return NULL;
|
||||
|
||||
pmdl = fd_msg_pmdl_get(qry);
|
||||
if (!pmdl)
|
||||
return NULL;
|
||||
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&pmdl->lock), );
|
||||
/* Search in the list for an item with the same handle. The list is ordered by this handle */
|
||||
for (li=pmdl->sentinel.next; li != &pmdl->sentinel; li = li->next) {
|
||||
struct pmd_list_item * pli = (struct pmd_list_item *) li;
|
||||
if (pli->hdl == data_hdl)
|
||||
ret = &pli->pmd;
|
||||
if (pli->hdl >= data_hdl)
|
||||
break;
|
||||
}
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&pmdl->lock), );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Create a mask */
|
||||
uint32_t fd_hook_mask_helper(int dummy, ...)
|
||||
{
|
||||
va_list ap;
|
||||
uint32_t ret = 0;
|
||||
int next;
|
||||
|
||||
va_start(ap, dummy);
|
||||
while ((next = va_arg(ap, int)) >= 0) {
|
||||
if (next > HOOK_LAST)
|
||||
break; /* invalid parameter */
|
||||
ret |= (1<<next);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static pthread_mutex_t hook_default_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
static char * hook_default_buf = NULL;
|
||||
static size_t hook_default_len = 0;
|
||||
|
||||
/* The function that does the work of calling the extension's callbacks and also managing the permessagedata structures */
|
||||
void fd_hook_call(enum fd_hook_type type, struct msg * msg, struct fd_peer * peer, void * other, struct fd_msg_pmdl * pmdl)
|
||||
{
|
||||
struct fd_list * li;
|
||||
ASSERT(type <= HOOK_LAST);
|
||||
int call_default = 0;
|
||||
|
||||
/* lock the list of hooks for this type */
|
||||
CHECK_POSIX_DO( pthread_rwlock_rdlock(&HS_array[type].rwlock), );
|
||||
|
||||
pthread_cleanup_push( fd_cleanup_rwlock, &HS_array[type].rwlock );
|
||||
|
||||
if (FD_IS_LIST_EMPTY(&HS_array[type].sentinel)) {
|
||||
call_default = 1;
|
||||
} else {
|
||||
/* for each registered hook */
|
||||
for (li = HS_array[type].sentinel.next; li != &HS_array[type].sentinel; li = li->next) {
|
||||
struct fd_hook_hdl * h = (struct fd_hook_hdl *)li->o;
|
||||
struct fd_hook_permsgdata * pmd = NULL;
|
||||
|
||||
/* do we need to handle pmd ? */
|
||||
if (h->data_hdl && pmdl) {
|
||||
pmd = get_or_create_pmd(pmdl, h);
|
||||
}
|
||||
|
||||
/* Now, call this callback */
|
||||
(*h->fd_hook_cb)(type, msg, &peer->p_hdr, other, pmd, h->regdata);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(0);
|
||||
|
||||
/* done */
|
||||
CHECK_POSIX_DO( pthread_rwlock_unlock(&HS_array[type].rwlock), );
|
||||
|
||||
if (call_default) {
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&hook_default_mtx), );
|
||||
|
||||
pthread_cleanup_push( fd_cleanup_mutex, &hook_default_mtx );
|
||||
|
||||
/* There was no registered handler, default behavior for this hook */
|
||||
switch (type) {
|
||||
case HOOK_DATA_RECEIVED: {
|
||||
struct fd_cnx_rcvdata *rcv_data = other;
|
||||
LOG_A("RCV: %zd bytes", rcv_data->length);
|
||||
break;
|
||||
}
|
||||
|
||||
case HOOK_MESSAGE_RECEIVED: {
|
||||
CHECK_MALLOC_DO(fd_msg_dump_summary(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
|
||||
LOG_D("RCV from '%s': %s", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", hook_default_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
case HOOK_MESSAGE_LOCAL: {
|
||||
CHECK_MALLOC_DO(fd_msg_dump_full(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
|
||||
LOG_A("Handled to framework for sending: %s", hook_default_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
case HOOK_MESSAGE_SENDING: {
|
||||
LOG_A("SENDING message to '%s'", peer ? peer->p_hdr.info.pi_diamid : "<unknown>");
|
||||
break;
|
||||
}
|
||||
|
||||
case HOOK_MESSAGE_SENT: {
|
||||
CHECK_MALLOC_DO(fd_msg_dump_summary(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
|
||||
LOG_D("SENT to '%s': %s", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", hook_default_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
case HOOK_MESSAGE_FAILOVER: {
|
||||
CHECK_MALLOC_DO(fd_msg_dump_summary(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
|
||||
LOG_D("Failing over message sent to '%s': %s", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", hook_default_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
case HOOK_MESSAGE_PARSING_ERROR: {
|
||||
if (msg) {
|
||||
DiamId_t id = NULL;
|
||||
if (!fd_msg_source_get( msg, &id, NULL ))
|
||||
id = (DiamId_t)"<error getting source>";
|
||||
|
||||
if (!id)
|
||||
id = (DiamId_t)"<local>";
|
||||
|
||||
CHECK_MALLOC_DO(fd_msg_dump_treeview(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
|
||||
|
||||
LOG_E("Parsing error: '%s' for the following message received from '%s':", (char *)other, (char *)id);
|
||||
LOG_SPLIT(FD_LOG_ERROR, " ", hook_default_buf, NULL);
|
||||
} else {
|
||||
struct fd_cnx_rcvdata *rcv_data = other;
|
||||
CHECK_MALLOC_DO(fd_dump_extend_hexdump(&hook_default_buf, &hook_default_len, NULL, rcv_data->buffer, rcv_data->length, 0, 0), break);
|
||||
LOG_E("Parsing error: cannot parse %zdB buffer from '%s': %s", rcv_data->length, peer ? peer->p_hdr.info.pi_diamid : "<unknown>", hook_default_buf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case HOOK_MESSAGE_PARSING_ERROR2: {
|
||||
CHECK_MALLOC_DO(fd_msg_dump_treeview(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
|
||||
|
||||
LOG_E("Returning following message after parsing error:");
|
||||
LOG_SPLIT(FD_LOG_ERROR, " ", hook_default_buf, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
case HOOK_MESSAGE_ROUTING_ERROR: {
|
||||
CHECK_MALLOC_DO(fd_msg_dump_treeview(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
|
||||
LOG_E("Routing error: '%s' for the following message:", (char *)other);
|
||||
LOG_SPLIT(FD_LOG_ERROR, " ", hook_default_buf, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
case HOOK_MESSAGE_ROUTING_FORWARD: {
|
||||
CHECK_MALLOC_DO(fd_msg_dump_summary(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
|
||||
LOG_D("FORWARDING: %s", hook_default_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
case HOOK_MESSAGE_ROUTING_LOCAL: {
|
||||
CHECK_MALLOC_DO(fd_msg_dump_summary(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
|
||||
LOG_D("DISPATCHING: %s", hook_default_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
case HOOK_MESSAGE_DROPPED: {
|
||||
CHECK_MALLOC_DO(fd_msg_dump_treeview(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
|
||||
LOG_E("Message discarded ('%s'):", (char *)other);
|
||||
LOG_SPLIT(FD_LOG_ERROR, " ", hook_default_buf, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
case HOOK_PEER_CONNECT_FAILED: {
|
||||
if (msg) {
|
||||
CHECK_MALLOC_DO(fd_msg_dump_full(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
|
||||
LOG_N("Connection to '%s' failed: '%s'; CER/CEA dump:", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", (char *)other);
|
||||
LOG_SPLIT(FD_LOG_NOTICE, " ", hook_default_buf, NULL);
|
||||
} else {
|
||||
LOG_D("Connection to '%s' failed: %s", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", (char *)other);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case HOOK_PEER_CONNECT_SUCCESS: {
|
||||
DiamId_t id = NULL;
|
||||
if ((!fd_msg_source_get( msg, &id, NULL )) && (id == NULL)) { /* The CEA is locally issued */
|
||||
fd_msg_answ_getq(msg, &msg); /* We dump the CER in that case */
|
||||
}
|
||||
CHECK_MALLOC_DO(fd_msg_dump_full(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
|
||||
char protobuf[40];
|
||||
if (peer) {
|
||||
CHECK_FCT_DO(fd_peer_cnx_proto_info(&peer->p_hdr, protobuf, sizeof(protobuf)), break );
|
||||
} else {
|
||||
protobuf[0] = '-';
|
||||
protobuf[1] = '\0';
|
||||
}
|
||||
LOG_N("Connected to '%s' (%s), remote capabilities: ", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", protobuf);
|
||||
LOG_SPLIT(FD_LOG_NOTICE, " ", hook_default_buf, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pthread_cleanup_pop(0);
|
||||
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&hook_default_mtx), );
|
||||
}
|
||||
}
|
||||
452
plat/diameter/libfdcore/messages.c
Normal file
452
plat/diameter/libfdcore/messages.c
Normal file
@@ -0,0 +1,452 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2015, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
static struct dict_object * dict_avp_SI = NULL; /* Session-Id */
|
||||
static struct dict_object * dict_avp_OH = NULL; /* Origin-Host */
|
||||
static struct dict_object * dict_avp_OR = NULL; /* Origin-Realm */
|
||||
static struct dict_object * dict_avp_EM = NULL; /* Error-Message */
|
||||
static struct dict_object * dict_avp_ERH = NULL; /* Error-Reporting-Host */
|
||||
static struct dict_object * dict_avp_FAVP= NULL; /* Failed-AVP */
|
||||
static struct dict_object * dict_avp_RC = NULL; /* Result-Code */
|
||||
struct dict_object * fd_dict_avp_OSI = NULL; /* Origin-State-Id */
|
||||
struct dict_object * fd_dict_cmd_CER = NULL; /* Capabilities-Exchange-Request */
|
||||
struct dict_object * fd_dict_cmd_DWR = NULL; /* Device-Watchdog-Request */
|
||||
struct dict_object * fd_dict_avp_DC = NULL; /* Disconnect-Cause */
|
||||
struct dict_object * fd_dict_cmd_DPR = NULL; /* Disconnect-Peer-Request */
|
||||
|
||||
/* Resolve the dictionary objects */
|
||||
int fd_msg_init(void)
|
||||
{
|
||||
TRACE_ENTRY("");
|
||||
|
||||
/* Initialize the dictionary objects that we may use frequently */
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &dict_avp_SI , ENOENT) );
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &dict_avp_OH , ENOENT) );
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &dict_avp_OR , ENOENT) );
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-State-Id", &fd_dict_avp_OSI , ENOENT) );
|
||||
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &dict_avp_RC , ENOENT) );
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Message", &dict_avp_EM , ENOENT) );
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Reporting-Host", &dict_avp_ERH , ENOENT) );
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Failed-AVP", &dict_avp_FAVP, ENOENT) );
|
||||
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Disconnect-Cause", &fd_dict_avp_DC , ENOENT) );
|
||||
|
||||
CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &fd_dict_cmd_CER, ENOENT ) );
|
||||
CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &fd_dict_cmd_DWR, ENOENT ) );
|
||||
CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Disconnect-Peer-Request", &fd_dict_cmd_DPR, ENOENT ) );
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add Origin-Host, Origin-Realm, Origin-State-Id AVPS at the end of the message */
|
||||
int fd_msg_add_origin ( struct msg * msg, int osi )
|
||||
{
|
||||
union avp_value val;
|
||||
struct avp * avp_OH = NULL;
|
||||
struct avp * avp_OR = NULL;
|
||||
struct avp * avp_OSI = NULL;
|
||||
|
||||
TRACE_ENTRY("%p", msg);
|
||||
CHECK_PARAMS( msg );
|
||||
|
||||
/* Create the Origin-Host AVP */
|
||||
CHECK_FCT( fd_msg_avp_new( dict_avp_OH, 0, &avp_OH ) );
|
||||
|
||||
/* Set its value */
|
||||
memset(&val, 0, sizeof(val));
|
||||
val.os.data = (os0_t)fd_g_config->cnf_diamid;
|
||||
val.os.len = fd_g_config->cnf_diamid_len;
|
||||
CHECK_FCT( fd_msg_avp_setvalue( avp_OH, &val ) );
|
||||
|
||||
/* Add it to the message */
|
||||
CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OH ) );
|
||||
|
||||
|
||||
/* Create the Origin-Realm AVP */
|
||||
CHECK_FCT( fd_msg_avp_new( dict_avp_OR, 0, &avp_OR ) );
|
||||
|
||||
/* Set its value */
|
||||
memset(&val, 0, sizeof(val));
|
||||
val.os.data = (os0_t)fd_g_config->cnf_diamrlm;
|
||||
val.os.len = fd_g_config->cnf_diamrlm_len;
|
||||
CHECK_FCT( fd_msg_avp_setvalue( avp_OR, &val ) );
|
||||
|
||||
/* Add it to the message */
|
||||
CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OR ) );
|
||||
|
||||
if (osi) {
|
||||
/* Create the Origin-State-Id AVP */
|
||||
CHECK_FCT( fd_msg_avp_new( fd_dict_avp_OSI, 0, &avp_OSI ) );
|
||||
|
||||
/* Set its value */
|
||||
memset(&val, 0, sizeof(val));
|
||||
val.u32 = fd_g_config->cnf_orstateid;
|
||||
CHECK_FCT( fd_msg_avp_setvalue( avp_OSI, &val ) );
|
||||
|
||||
/* Add it to the message */
|
||||
CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OSI ) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create a new Session-Id and add at the beginning of the message. */
|
||||
int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen )
|
||||
{
|
||||
union avp_value val;
|
||||
struct avp * avp = NULL;
|
||||
struct session * sess = NULL;
|
||||
os0_t sid;
|
||||
size_t sidlen;
|
||||
|
||||
TRACE_ENTRY("%p %p %zd", msg, opt, optlen);
|
||||
CHECK_PARAMS( msg );
|
||||
|
||||
/* Check there is not already a session in the message */
|
||||
CHECK_FCT( fd_msg_sess_get(fd_g_config->cnf_dict, msg, &sess, NULL) );
|
||||
CHECK_PARAMS( sess == NULL );
|
||||
|
||||
/* Ok, now create the session */
|
||||
CHECK_FCT( fd_sess_new ( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, opt, optlen ) );
|
||||
CHECK_FCT( fd_sess_getsid( sess, &sid, &sidlen) );
|
||||
|
||||
/* Create an AVP to hold it */
|
||||
CHECK_FCT( fd_msg_avp_new( dict_avp_SI, 0, &avp ) );
|
||||
|
||||
/* Set its value */
|
||||
memset(&val, 0, sizeof(val));
|
||||
val.os.data = sid;
|
||||
val.os.len = sidlen;
|
||||
CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
|
||||
|
||||
/* Add it to the message */
|
||||
CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_FIRST_CHILD, avp ) );
|
||||
|
||||
/* Save the session associated with the message */
|
||||
CHECK_FCT( fd_msg_sess_set( msg, sess) );
|
||||
|
||||
/* Done! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Add Result-Code and eventually Failed-AVP, Error-Message and Error-Reporting-Host AVPs */
|
||||
int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id )
|
||||
{
|
||||
union avp_value val;
|
||||
struct avp * avp_RC = NULL;
|
||||
struct avp * avp_EM = NULL;
|
||||
struct avp * avp_ERH = NULL;
|
||||
struct avp * avp_FAVP= NULL;
|
||||
uint32_t rc_val = 0;
|
||||
int set_e_bit=0;
|
||||
int std_err_msg=0;
|
||||
|
||||
TRACE_ENTRY("%p %s %p %p %d", msg, rescode, errormsg, optavp, type_id);
|
||||
|
||||
CHECK_PARAMS( msg && rescode );
|
||||
|
||||
/* Find the enum value corresponding to the rescode string, this will give the class of error */
|
||||
{
|
||||
struct dict_object * enum_obj = NULL;
|
||||
struct dict_enumval_request req;
|
||||
memset(&req, 0, sizeof(struct dict_enumval_request));
|
||||
|
||||
/* First, get the enumerated type of the Result-Code AVP (this is fast, no need to cache the object) */
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &(req.type_obj), ENOENT ) );
|
||||
|
||||
/* Now search for the value given as parameter */
|
||||
req.search.enum_name = rescode;
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &req, &enum_obj, ENOTSUP) );
|
||||
|
||||
/* finally retrieve its data */
|
||||
CHECK_FCT_DO( fd_dict_getval( enum_obj, &(req.search) ), return EINVAL );
|
||||
|
||||
/* copy the found value, we're done */
|
||||
rc_val = req.search.enum_value.u32;
|
||||
}
|
||||
|
||||
if (type_id == 1) {
|
||||
/* Add the Origin-Host and Origin-Realm AVP */
|
||||
CHECK_FCT( fd_msg_add_origin ( msg, 0 ) );
|
||||
}
|
||||
|
||||
/* Create the Result-Code AVP */
|
||||
CHECK_FCT( fd_msg_avp_new( dict_avp_RC, 0, &avp_RC ) );
|
||||
|
||||
/* Set its value */
|
||||
memset(&val, 0, sizeof(val));
|
||||
val.u32 = rc_val;
|
||||
CHECK_FCT( fd_msg_avp_setvalue( avp_RC, &val ) );
|
||||
|
||||
/* Add it to the message */
|
||||
CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_RC ) );
|
||||
|
||||
if (type_id == 2) {
|
||||
/* Add the Error-Reporting-Host AVP */
|
||||
|
||||
CHECK_FCT( fd_msg_avp_new( dict_avp_ERH, 0, &avp_ERH ) );
|
||||
|
||||
/* Set its value */
|
||||
memset(&val, 0, sizeof(val));
|
||||
val.os.data = (uint8_t *)fd_g_config->cnf_diamid;
|
||||
val.os.len = fd_g_config->cnf_diamid_len;
|
||||
CHECK_FCT( fd_msg_avp_setvalue( avp_ERH, &val ) );
|
||||
|
||||
/* Add it to the message */
|
||||
CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_ERH ) );
|
||||
|
||||
}
|
||||
|
||||
/* Now add the optavp in a FailedAVP if provided */
|
||||
if (optavp) {
|
||||
struct avp * optavp_cpy = NULL;
|
||||
struct avp_hdr *opt_hdr, *optcpy_hdr;
|
||||
struct dict_object * opt_model = NULL;
|
||||
int is_grouped = 0;
|
||||
|
||||
/* Create the Failed-AVP AVP */
|
||||
CHECK_FCT( fd_msg_avp_new( dict_avp_FAVP, 0, &avp_FAVP ) );
|
||||
|
||||
/* Was this AVP a grouped one? Best effort only here */
|
||||
if (!fd_msg_model ( optavp, &opt_model ) && (opt_model != NULL)) {
|
||||
struct dict_avp_data dictdata;
|
||||
CHECK_FCT( fd_dict_getval(opt_model, &dictdata) );
|
||||
if (dictdata.avp_basetype == AVP_TYPE_GROUPED)
|
||||
is_grouped = 1;
|
||||
}
|
||||
|
||||
/* Create a new AVP with a copy of the data of the invalid or missing AVP */
|
||||
optavp_cpy = optavp;
|
||||
|
||||
if (is_grouped) {
|
||||
CHECK_FCT( fd_msg_avp_new( opt_model, 0, &optavp_cpy) );
|
||||
} else {
|
||||
CHECK_FCT( fd_msg_avp_new( NULL, AVPFL_SET_BLANK_VALUE | AVPFL_SET_RAWDATA_FROM_AVP, &optavp_cpy) );
|
||||
|
||||
CHECK_FCT( fd_msg_avp_hdr(optavp, &opt_hdr) );
|
||||
CHECK_FCT( fd_msg_avp_hdr(optavp_cpy, &optcpy_hdr) );
|
||||
memcpy(optcpy_hdr, opt_hdr, sizeof(struct avp_hdr));
|
||||
}
|
||||
|
||||
/* Add the passed AVP inside it */
|
||||
CHECK_FCT( fd_msg_avp_add( avp_FAVP, MSG_BRW_LAST_CHILD, optavp_cpy ) );
|
||||
|
||||
/* And add to the message */
|
||||
CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_FAVP ) );
|
||||
}
|
||||
|
||||
|
||||
/* Deal with the 'E' bit and the error message */
|
||||
switch (rc_val / 1000) {
|
||||
case 1: /* Informational */
|
||||
case 2: /* Success */
|
||||
/* Nothing special here: no E bit, no error message unless one is specified */
|
||||
break;
|
||||
|
||||
case 3: /* Protocol Errors */
|
||||
set_e_bit = 1;
|
||||
std_err_msg = 1;
|
||||
break;
|
||||
|
||||
case 4: /* Transcient Failure */
|
||||
case 5: /* Permanent Failure */
|
||||
default:
|
||||
std_err_msg = 1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
struct msg_hdr * hdr = NULL;
|
||||
|
||||
CHECK_FCT( fd_msg_hdr( msg, &hdr ) );
|
||||
|
||||
if (set_e_bit)
|
||||
hdr->msg_flags |= CMD_FLAG_ERROR;
|
||||
else
|
||||
hdr->msg_flags &= ~ CMD_FLAG_ERROR;
|
||||
}
|
||||
|
||||
if (std_err_msg || errormsg) {
|
||||
/* Add the Error-Message AVP */
|
||||
|
||||
CHECK_FCT( fd_msg_avp_new( dict_avp_EM, 0, &avp_EM ) );
|
||||
|
||||
/* Set its value */
|
||||
memset(&val, 0, sizeof(val));
|
||||
|
||||
if (errormsg) {
|
||||
val.os.data = (uint8_t *)errormsg;
|
||||
val.os.len = strlen(errormsg);
|
||||
} else {
|
||||
val.os.data = (uint8_t *)rescode;
|
||||
val.os.len = strlen(rescode);
|
||||
}
|
||||
CHECK_FCT( fd_msg_avp_setvalue( avp_EM, &val ) );
|
||||
|
||||
/* Add it to the message */
|
||||
CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_EM ) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fd_msg_send_int( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout )
|
||||
{
|
||||
struct msg_hdr *hdr;
|
||||
DiamId_t diamid;
|
||||
|
||||
/* Save the callback in the message, with the timeout */
|
||||
CHECK_FCT( fd_msg_anscb_associate( *pmsg, anscb, data, expirecb, timeout ) );
|
||||
|
||||
/* If this is a new request, call the HOOK_MESSAGE_LOCAL hook */
|
||||
if ( (fd_msg_hdr(*pmsg, &hdr) == 0)
|
||||
&& (hdr->msg_flags & CMD_FLAG_REQUEST)
|
||||
&& (fd_msg_source_get(*pmsg, &diamid, NULL) == 0)
|
||||
&& (diamid == NULL)) {
|
||||
fd_hook_call(HOOK_MESSAGE_LOCAL, *pmsg, NULL, NULL, fd_msg_pmdl_get(*pmsg));
|
||||
}
|
||||
|
||||
/* Post the message in the outgoing queue */
|
||||
CHECK_FCT( fd_fifo_post(fd_g_outgoing, pmsg) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send a message and optionally register a callback for an answer */
|
||||
int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data )
|
||||
{
|
||||
TRACE_ENTRY("%p %p %p", pmsg, anscb, data);
|
||||
CHECK_PARAMS( pmsg );
|
||||
|
||||
return fd_msg_send_int(pmsg, anscb, data, NULL, NULL);
|
||||
}
|
||||
|
||||
/* The variation of the same function with a timeout callback */
|
||||
int fd_msg_send_timeout ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout )
|
||||
{
|
||||
TRACE_ENTRY("%p %p %p %p %p", pmsg, anscb, data, expirecb, timeout);
|
||||
CHECK_PARAMS( pmsg && expirecb && timeout );
|
||||
|
||||
return fd_msg_send_int(pmsg, anscb, data, expirecb, timeout);
|
||||
}
|
||||
|
||||
|
||||
/* Parse a message against our dictionary, and in case of error log and eventually build the error reply -- returns the parsing status */
|
||||
int fd_msg_parse_or_error( struct msg ** msg, struct msg **error)
|
||||
{
|
||||
int ret = 0;
|
||||
struct msg * m;
|
||||
struct msg_hdr * hdr = NULL;
|
||||
struct fd_pei pei;
|
||||
|
||||
TRACE_ENTRY("%p", msg);
|
||||
|
||||
CHECK_PARAMS(msg && *msg && error);
|
||||
m = *msg;
|
||||
*error = NULL;
|
||||
|
||||
/* Parse the message against our dictionary */
|
||||
ret = fd_msg_parse_rules ( m, fd_g_config->cnf_dict, &pei);
|
||||
if ((ret != EBADMSG) /* Parsing grouped AVP failed / Conflicting rule found */
|
||||
&& (ret != ENOTSUP)) /* Command is not supported / Mandatory AVP is not supported */
|
||||
return ret; /* 0 or another error */
|
||||
|
||||
/* Log */
|
||||
fd_hook_call(HOOK_MESSAGE_PARSING_ERROR, m, NULL, pei.pei_message ?: pei.pei_errcode, fd_msg_pmdl_get(m));
|
||||
|
||||
CHECK_FCT( fd_msg_hdr(m, &hdr) );
|
||||
|
||||
/* Now create an answer error if the message is a query */
|
||||
if (hdr->msg_flags & CMD_FLAG_REQUEST) {
|
||||
|
||||
/* Create the error message */
|
||||
CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &m, pei.pei_protoerr ? MSGFL_ANSW_ERROR : 0 ) );
|
||||
|
||||
/* Set the error code */
|
||||
CHECK_FCT( fd_msg_rescode_set(m, pei.pei_errcode, pei.pei_message, pei.pei_avp, 1 ) );
|
||||
|
||||
/* free the pei AVP to avoid memory leak */
|
||||
if (pei.pei_avp_free) {
|
||||
fd_msg_free(pei.pei_avp);
|
||||
}
|
||||
|
||||
*msg = NULL;
|
||||
*error = m;
|
||||
|
||||
} else {
|
||||
do { /* Rescue error messages */
|
||||
struct avp * avp;
|
||||
union avp_value * rc = NULL;
|
||||
|
||||
/* Search the Result-Code AVP */
|
||||
CHECK_FCT_DO( fd_msg_browse(*msg, MSG_BRW_FIRST_CHILD, &avp, NULL), break );
|
||||
while (avp) {
|
||||
struct avp_hdr * ahdr;
|
||||
CHECK_FCT_DO( fd_msg_avp_hdr( avp, &ahdr ), break );
|
||||
|
||||
if ((ahdr->avp_code == AC_RESULT_CODE) && (! (ahdr->avp_flags & AVP_FLAG_VENDOR)) ) {
|
||||
/* Parse this AVP */
|
||||
ASSERT( ahdr->avp_value );
|
||||
rc = ahdr->avp_value;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Go to next AVP */
|
||||
CHECK_FCT_DO( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL), break );
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
switch (rc->u32 / 1000) {
|
||||
case 1: /* 1xxx : Informational */
|
||||
case 2: /* 2xxx : Sucess */
|
||||
/* In these cases, we want the message to validate the ABNF, so we will discard the bad message */
|
||||
break;
|
||||
|
||||
default: /* Other errors */
|
||||
/* We let the application decide what to do with the message, we rescue it */
|
||||
*error = m;
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
}
|
||||
|
||||
return EBADMSG; /* We convert ENOTSUP to EBADMSG as well */
|
||||
}
|
||||
1112
plat/diameter/libfdcore/p_ce.c
Normal file
1112
plat/diameter/libfdcore/p_ce.c
Normal file
File diff suppressed because it is too large
Load Diff
357
plat/diameter/libfdcore/p_cnx.c
Normal file
357
plat/diameter/libfdcore/p_cnx.c
Normal file
@@ -0,0 +1,357 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
|
||||
/* TODO: change the behavior to handle properly forced ordering at beginning & end of OPEN state */
|
||||
|
||||
/* This file contains code used by a peer state machine to initiate a connection to remote peer */
|
||||
|
||||
struct next_conn {
|
||||
struct fd_list chain;
|
||||
int proto; /* Protocol of the next attempt */
|
||||
union {
|
||||
sSS ss; /* The address, only for TCP */
|
||||
sSA4 sin;
|
||||
sSA6 sin6;
|
||||
};
|
||||
uint16_t port; /* The port, for SCTP (included in ss for TCP) */
|
||||
int dotls; /* Handshake TLS after connection ? */
|
||||
};
|
||||
|
||||
static __inline__ void failed_connection_attempt(struct fd_peer * peer)
|
||||
{
|
||||
/* Simply remove the first item in the list if not empty */
|
||||
if (! FD_IS_LIST_EMPTY(&peer->p_connparams) ) {
|
||||
struct fd_list * li = peer->p_connparams.next;
|
||||
fd_list_unlink(li);
|
||||
free(li);
|
||||
}
|
||||
}
|
||||
|
||||
static void empty_connection_list(struct fd_peer * peer)
|
||||
{
|
||||
/* Remove all items */
|
||||
while (!FD_IS_LIST_EMPTY(&peer->p_connparams)) {
|
||||
failed_connection_attempt(peer);
|
||||
}
|
||||
}
|
||||
|
||||
static int prepare_connection_list(struct fd_peer * peer)
|
||||
{
|
||||
struct fd_list * li, *last_prio;
|
||||
struct next_conn * new;
|
||||
|
||||
uint16_t port_no; /* network order */
|
||||
int dotls_immediate;
|
||||
int count = 0;
|
||||
|
||||
TRACE_ENTRY("%p", peer);
|
||||
|
||||
/* Resolve peer address(es) if needed */
|
||||
if (FD_IS_LIST_EMPTY(&peer->p_hdr.info.pi_endpoints)) {
|
||||
struct addrinfo hints, *ai, *aip;
|
||||
int ret;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
ret = getaddrinfo(peer->p_hdr.info.pi_diamid, NULL, &hints, &ai);
|
||||
if (ret) {
|
||||
TRACE_DEBUG(INFO, "Unable to resolve address for peer '%s' (%s), aborting", peer->p_hdr.info.pi_diamid, gai_strerror(ret));
|
||||
if (ret != EAI_AGAIN)
|
||||
fd_psm_terminate( peer, NULL );
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (aip = ai; aip != NULL; aip = aip->ai_next) {
|
||||
CHECK_FCT( fd_ep_add_merge( &peer->p_hdr.info.pi_endpoints, aip->ai_addr, aip->ai_addrlen, EP_FL_DISC ) );
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
|
||||
/* Remove addresses from unwanted family */
|
||||
if (peer->p_hdr.info.config.pic_flags.pro3) {
|
||||
CHECK_FCT( fd_ep_filter_family(
|
||||
&peer->p_hdr.info.pi_endpoints,
|
||||
(peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP) ?
|
||||
AF_INET
|
||||
: AF_INET6));
|
||||
}
|
||||
if (fd_g_config->cnf_flags.no_ip4) {
|
||||
CHECK_FCT( fd_ep_filter_family(
|
||||
&peer->p_hdr.info.pi_endpoints,
|
||||
AF_INET6));
|
||||
}
|
||||
if (fd_g_config->cnf_flags.no_ip6) {
|
||||
CHECK_FCT( fd_ep_filter_family(
|
||||
&peer->p_hdr.info.pi_endpoints,
|
||||
AF_INET));
|
||||
}
|
||||
|
||||
/* We don't use the alternate addresses that were sent by the remote peer */
|
||||
CHECK_FCT( fd_ep_clearflags(&peer->p_hdr.info.pi_endpoints, EP_FL_ADV) );
|
||||
|
||||
|
||||
/* Now check we have at least one address to attempt */
|
||||
if (FD_IS_LIST_EMPTY(&peer->p_hdr.info.pi_endpoints)) {
|
||||
TRACE_DEBUG(INFO, "No address %savailable to connect to peer '%s', aborting",
|
||||
peer->p_hdr.info.config.pic_flags.pro3 ? "in the configured family " : "", peer->p_hdr.info.pi_diamid);
|
||||
fd_psm_terminate( peer, NULL );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if we are able to communicate with this peer */
|
||||
if (fd_g_config->cnf_sec_data.tls_disabled && ( peer->p_hdr.info.config.pic_flags.sec != PI_SEC_NONE)) {
|
||||
LOG_E("Peer '%s' not configured for No_TLS and TLS is locally disabled; giving up connection attempts",
|
||||
peer->p_hdr.info.pi_diamid);
|
||||
fd_psm_terminate( peer, NULL );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cleanup any previous list */
|
||||
empty_connection_list(peer);
|
||||
|
||||
/* Prepare the parameters */
|
||||
if ((peer->p_hdr.info.config.pic_flags.sec != PI_SEC_DEFAULT) || (fd_g_config->cnf_flags.tls_alg)) {
|
||||
dotls_immediate = 0;
|
||||
port_no = htons(peer->p_hdr.info.config.pic_port ?: DIAMETER_PORT);
|
||||
} else {
|
||||
dotls_immediate = 1;
|
||||
port_no = htons(peer->p_hdr.info.config.pic_port ?: DIAMETER_SECURE_PORT);
|
||||
}
|
||||
|
||||
last_prio = &peer->p_connparams;
|
||||
|
||||
/* Create TCP parameters unless specified otherwise */
|
||||
if ((!fd_g_config->cnf_flags.no_tcp) && (peer->p_hdr.info.config.pic_flags.pro4 != PI_P4_SCTP)) {
|
||||
for (li = peer->p_hdr.info.pi_endpoints.next; li != &peer->p_hdr.info.pi_endpoints; li = li->next) {
|
||||
struct fd_endpoint * ep = (struct fd_endpoint *)li;
|
||||
|
||||
CHECK_MALLOC( new = malloc(sizeof(struct next_conn)) );
|
||||
memset(new, 0, sizeof(struct next_conn));
|
||||
fd_list_init(&new->chain, new);
|
||||
|
||||
new->proto = IPPROTO_TCP;
|
||||
|
||||
memcpy( &new->ss, &ep->ss, sizeof(sSS) );
|
||||
switch (new->ss.ss_family) {
|
||||
case AF_INET:
|
||||
new->sin.sin_port = port_no;
|
||||
break;
|
||||
case AF_INET6:
|
||||
new->sin6.sin6_port = port_no;
|
||||
break;
|
||||
default:
|
||||
free(new);
|
||||
continue; /* Move to the next endpoint */
|
||||
}
|
||||
|
||||
new->dotls = dotls_immediate;
|
||||
|
||||
/* Add the new entry to the appropriate position (conf and disc go first) */
|
||||
if (ep->flags & (EP_FL_CONF | EP_FL_DISC)) {
|
||||
fd_list_insert_after(last_prio, &new->chain);
|
||||
last_prio = &new->chain;
|
||||
} else {
|
||||
fd_list_insert_before(&peer->p_connparams, &new->chain);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now, add the SCTP entry, if not disabled */
|
||||
#ifndef DISABLE_SCTP
|
||||
if ((!fd_g_config->cnf_flags.no_sctp) && (peer->p_hdr.info.config.pic_flags.pro4 != PI_P4_TCP)) {
|
||||
struct next_conn * new;
|
||||
|
||||
CHECK_MALLOC( new = malloc(sizeof(struct next_conn)) );
|
||||
memset(new, 0, sizeof(struct next_conn));
|
||||
fd_list_init(&new->chain, new);
|
||||
|
||||
new->proto = IPPROTO_SCTP;
|
||||
new->port = ntohs(port_no); /* back to host byte order... */
|
||||
new->dotls = dotls_immediate;
|
||||
|
||||
/* Add the new entry to the appropriate position (depending on preferences) */
|
||||
if ((fd_g_config->cnf_flags.pr_tcp) || (peer->p_hdr.info.config.pic_flags.alg == PI_ALGPREF_TCP)) {
|
||||
fd_list_insert_after(last_prio, &new->chain);
|
||||
} else {
|
||||
fd_list_insert_after(&peer->p_connparams, &new->chain); /* very first position */
|
||||
}
|
||||
count++;
|
||||
}
|
||||
#endif /* DISABLE_SCTP */
|
||||
|
||||
LOG_D("Prepared %d sets of connection parameters to peer %s", count, peer->p_hdr.info.pi_diamid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* The thread that attempts the connection */
|
||||
static void * connect_thr(void * arg)
|
||||
{
|
||||
struct fd_peer * peer = arg;
|
||||
struct cnxctx * cnx = NULL;
|
||||
struct next_conn * nc = NULL;
|
||||
int rebuilt = 0;
|
||||
int fatal_error=0;
|
||||
|
||||
TRACE_ENTRY("%p", arg);
|
||||
CHECK_PARAMS_DO( CHECK_PEER(peer), return NULL );
|
||||
|
||||
/* Set the thread name */
|
||||
{
|
||||
char buf[48];
|
||||
snprintf(buf, sizeof(buf), "ConnTo:%s", peer->p_hdr.info.pi_diamid);
|
||||
fd_log_threadname ( buf );
|
||||
}
|
||||
|
||||
do {
|
||||
/* Rebuild the list if needed, if it is empty -- but at most once */
|
||||
if (FD_IS_LIST_EMPTY(&peer->p_connparams)) {
|
||||
if (! rebuilt) {
|
||||
CHECK_FCT_DO( fatal_error = prepare_connection_list(peer), goto out );
|
||||
rebuilt ++;
|
||||
}
|
||||
if (FD_IS_LIST_EMPTY(&peer->p_connparams)) {
|
||||
/* We encountered an error or we have looped over all the addresses of the peer. */
|
||||
fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, peer, "All connection attempts failed, will retry later", NULL);
|
||||
|
||||
CHECK_FCT_DO( fatal_error = fd_event_send(peer->p_events, FDEVP_CNX_FAILED, 0, NULL), goto out );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt connection to the first entry */
|
||||
nc = (struct next_conn *)(peer->p_connparams.next);
|
||||
|
||||
switch (nc->proto) {
|
||||
case IPPROTO_TCP:
|
||||
cnx = fd_cnx_cli_connect_tcp((sSA *)&nc->ss, sSAlen(&nc->ss));
|
||||
break;
|
||||
#ifndef DISABLE_SCTP
|
||||
case IPPROTO_SCTP:
|
||||
cnx = fd_cnx_cli_connect_sctp((peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP) ? 1 : fd_g_config->cnf_flags.no_ip6,
|
||||
nc->port, &peer->p_hdr.info.pi_endpoints);
|
||||
break;
|
||||
#endif /* DISABLE_SCTP */
|
||||
}
|
||||
|
||||
if (cnx)
|
||||
break;
|
||||
|
||||
/* Pop these parameters and continue */
|
||||
failed_connection_attempt(peer);
|
||||
|
||||
pthread_testcancel();
|
||||
|
||||
} while (!cnx); /* and until cancellation or all addresses attempted without success */
|
||||
|
||||
/* Now, we have an established connection in cnx */
|
||||
|
||||
pthread_cleanup_push((void *)fd_cnx_destroy, cnx);
|
||||
|
||||
/* Set the hostname in the connection, so that handshake verifies the remote identity */
|
||||
fd_cnx_sethostname(cnx,peer->p_hdr.info.pi_diamid);
|
||||
|
||||
/* Handshake if needed (secure port) */
|
||||
if (nc->dotls) {
|
||||
CHECK_FCT_DO( fd_cnx_handshake(cnx, GNUTLS_CLIENT,
|
||||
ALGO_HANDSHAKE_3436,
|
||||
peer->p_hdr.info.config.pic_priority, NULL),
|
||||
{
|
||||
/* Handshake failed ... */
|
||||
fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, peer, "TLS Handshake failed", NULL);
|
||||
fd_cnx_destroy(cnx);
|
||||
empty_connection_list(peer);
|
||||
fd_ep_filter(&peer->p_hdr.info.pi_endpoints, EP_FL_CONF);
|
||||
goto out_pop;
|
||||
} );
|
||||
LOG_A("%s: TLS handshake successful.", peer->p_hdr.info.pi_diamid);
|
||||
} else {
|
||||
/* Prepare to receive the next message */
|
||||
CHECK_FCT_DO( fatal_error = fd_cnx_start_clear(cnx, 0), goto out_pop );
|
||||
}
|
||||
|
||||
/* Upon success, generate FDEVP_CNX_ESTABLISHED */
|
||||
CHECK_FCT_DO( fatal_error = fd_event_send(peer->p_events, FDEVP_CNX_ESTABLISHED, 0, cnx), );
|
||||
out_pop:
|
||||
;
|
||||
pthread_cleanup_pop(0);
|
||||
|
||||
out:
|
||||
|
||||
if (fatal_error) {
|
||||
|
||||
/* Cleanup the connection */
|
||||
if (cnx)
|
||||
fd_cnx_destroy(cnx);
|
||||
|
||||
/* Generate a termination event */
|
||||
CHECK_FCT_DO(fd_core_shutdown(), );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Initiate a connection attempt to a remote peer */
|
||||
int fd_p_cnx_init(struct fd_peer * peer)
|
||||
{
|
||||
TRACE_ENTRY("%p", peer);
|
||||
|
||||
/* Start the connect thread */
|
||||
CHECK_FCT( pthread_create(&peer->p_ini_thr, NULL, connect_thr, peer) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cancel a connection attempt */
|
||||
void fd_p_cnx_abort(struct fd_peer * peer, int cleanup_all)
|
||||
{
|
||||
TRACE_ENTRY("%p %d", peer, cleanup_all);
|
||||
CHECK_PARAMS_DO( CHECK_PEER(peer), return );
|
||||
|
||||
if (peer->p_ini_thr != (pthread_t)NULL) {
|
||||
CHECK_FCT_DO( fd_thr_term(&peer->p_ini_thr), /* continue */);
|
||||
failed_connection_attempt(peer);
|
||||
}
|
||||
|
||||
if (cleanup_all) {
|
||||
empty_connection_list(peer);
|
||||
}
|
||||
}
|
||||
|
||||
207
plat/diameter/libfdcore/p_dp.c
Normal file
207
plat/diameter/libfdcore/p_dp.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
/* This file contains code to handle Disconnect Peer messages (DPR and DPA) */
|
||||
|
||||
/* Delay to use before next reconnect attempt */
|
||||
int fd_p_dp_newdelay(struct fd_peer * peer)
|
||||
{
|
||||
int delay = peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc;
|
||||
|
||||
switch (peer->p_hdr.info.runtime.pir_lastDC) {
|
||||
case ACV_DC_REBOOTING:
|
||||
default:
|
||||
/* We use TcTimer to attempt reconnection */
|
||||
break;
|
||||
case ACV_DC_BUSY:
|
||||
/* No need to hammer the overloaded peer */
|
||||
delay *= 10;
|
||||
break;
|
||||
case ACV_DC_NOT_FRIEND:
|
||||
/* He does not want to speak to us... let's retry a *lot* later maybe */
|
||||
delay *= 200;
|
||||
break;
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
|
||||
/* Handle a received message */
|
||||
int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer)
|
||||
{
|
||||
long to_receive, to_send;
|
||||
TRACE_ENTRY("%p %d %p", msg, req, peer);
|
||||
|
||||
if (req) {
|
||||
/* We received a DPR, save the Disconnect-Cause and go to CLOSING_GRACE or terminate the connection */
|
||||
struct avp * dc;
|
||||
|
||||
CHECK_FCT( fd_msg_search_avp ( *msg, fd_dict_avp_DC, &dc ));
|
||||
if (dc) {
|
||||
struct avp_hdr * hdr;
|
||||
CHECK_FCT( fd_msg_avp_hdr( dc, &hdr ) );
|
||||
if (hdr->avp_value == NULL) {
|
||||
/* This is a sanity check */
|
||||
LOG_F("BUG: Unset value in Disconnect-Cause in DPR");
|
||||
ASSERT(0); /* To check if this really happens, and understand why... */
|
||||
}
|
||||
|
||||
/* save the cause */
|
||||
peer->p_hdr.info.runtime.pir_lastDC = hdr->avp_value->u32;
|
||||
}
|
||||
if (TRACE_BOOL(INFO)) {
|
||||
if (dc) {
|
||||
struct dict_object * dictobj;
|
||||
struct dict_enumval_request er;
|
||||
memset(&er, 0, sizeof(er));
|
||||
|
||||
/* prepare the request */
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, fd_dict_avp_DC, &er.type_obj, ENOENT ) );
|
||||
er.search.enum_value.u32 = peer->p_hdr.info.runtime.pir_lastDC;
|
||||
|
||||
/* Search the enum value */
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &er, &dictobj, 0 ) );
|
||||
if (dictobj) {
|
||||
CHECK_FCT( fd_dict_getval( dictobj, &er.search ) );
|
||||
TRACE_DEBUG(INFO, "Peer '%s' sent a DPR with cause: %s", peer->p_hdr.info.pi_diamid, er.search.enum_name);
|
||||
} else {
|
||||
TRACE_DEBUG(INFO, "Peer '%s' sent a DPR with unknown cause: %u", peer->p_hdr.info.pi_diamid, peer->p_hdr.info.runtime.pir_lastDC);
|
||||
}
|
||||
} else {
|
||||
TRACE_DEBUG(INFO, "Peer '%s' sent a DPR without Disconnect-Cause AVP", peer->p_hdr.info.pi_diamid);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now reply with a DPA */
|
||||
CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, 0 ) );
|
||||
CHECK_FCT( fd_msg_rescode_set( *msg, "DIAMETER_SUCCESS", NULL, NULL, 1 ) );
|
||||
|
||||
/* Do we have pending exchanges with this peer? */
|
||||
CHECK_FCT( fd_peer_get_load_pending(&peer->p_hdr, &to_receive, &to_send) );
|
||||
|
||||
if ((to_receive == 0) && (to_send == 0)) {
|
||||
/* No pending exchange, move to CLOSING directly */
|
||||
CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING) );
|
||||
|
||||
/* Now send the DPA */
|
||||
CHECK_FCT( fd_out_send( msg, NULL, peer, 0) );
|
||||
|
||||
/* and move to CLOSED */
|
||||
fd_psm_cleanup(peer, 0);
|
||||
|
||||
/* Reset the timer for next connection attempt -- we'll retry sooner or later depending on the disconnection cause */
|
||||
fd_psm_next_timeout(peer, 1, fd_p_dp_newdelay(peer));
|
||||
} else {
|
||||
/* We have pending exchanges, we move to CLOSING_GRACE which allows exchanges of answers but
|
||||
not new requests */
|
||||
CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING_GRACE) );
|
||||
fd_psm_next_timeout(peer, 0, GRACE_TIMEOUT);
|
||||
|
||||
/* Now send the DPA */
|
||||
CHECK_FCT( fd_out_send( msg, NULL, peer, 0) );
|
||||
}
|
||||
} else {
|
||||
/* We received a DPA */
|
||||
int curstate = fd_peer_getstate(peer);
|
||||
if (curstate != STATE_CLOSING_GRACE) {
|
||||
TRACE_DEBUG(INFO, "Ignoring DPA received in state %s", STATE_STR(curstate));
|
||||
}
|
||||
|
||||
/* In theory, we should control the Result-Code AVP. But since we will not go back to OPEN state here anyway, let's skip it */
|
||||
|
||||
/* TODO("Control Result-Code in the DPA") */
|
||||
CHECK_FCT_DO( fd_msg_free( *msg ), /* continue */ );
|
||||
*msg = NULL;
|
||||
|
||||
/* Do we still have pending exchanges with this peer? */
|
||||
CHECK_FCT( fd_peer_get_load_pending(&peer->p_hdr, &to_receive, &to_send) );
|
||||
if ((to_receive != 0) || (to_send != 0)) {
|
||||
TRACE_DEBUG(INFO, "Received DPA but pending load: [%ld, %ld], giving grace delay before closing", to_receive, to_send);
|
||||
fd_psm_next_timeout(peer, 0, GRACE_TIMEOUT);
|
||||
peer->p_flags.pf_localterm = 1;
|
||||
} else {
|
||||
/* otherwise, go to CLOSING state, the psm will handle terminating the connection */
|
||||
CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING) );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Start disconnection of a peer: send DPR */
|
||||
int fd_p_dp_initiate(struct fd_peer * peer, char * reason)
|
||||
{
|
||||
struct msg * msg = NULL;
|
||||
struct dict_object * dictobj = NULL;
|
||||
struct avp * avp = NULL;
|
||||
struct dict_enumval_request er;
|
||||
union avp_value val;
|
||||
|
||||
TRACE_ENTRY("%p %p", peer, reason);
|
||||
|
||||
/* Create a new DWR instance */
|
||||
CHECK_FCT( fd_msg_new ( fd_dict_cmd_DPR, MSGFL_ALLOC_ETEID, &msg ) );
|
||||
|
||||
/* Add the Origin information */
|
||||
CHECK_FCT( fd_msg_add_origin ( msg, 0 ) );
|
||||
|
||||
/* Add the Disconnect-Cause */
|
||||
CHECK_FCT( fd_msg_avp_new ( fd_dict_avp_DC, 0, &avp ) );
|
||||
|
||||
/* Search the value in the dictionary */
|
||||
memset(&er, 0, sizeof(er));
|
||||
CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, fd_dict_avp_DC, &er.type_obj, ENOENT ) );
|
||||
er.search.enum_name = reason ?: "REBOOTING";
|
||||
CHECK_FCT_DO( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &er, &dictobj, ENOENT ), { ASSERT(0); /* internal error: unknown reason */ } );
|
||||
CHECK_FCT( fd_dict_getval( dictobj, &er.search ) );
|
||||
|
||||
/* Set the value in the AVP */
|
||||
val.u32 = er.search.enum_value.u32;
|
||||
CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
|
||||
CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
|
||||
|
||||
/* Save the value also in the peer */
|
||||
peer->p_hdr.info.runtime.pir_lastDC = val.u32;
|
||||
|
||||
/* Update the peer state and timer */
|
||||
CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING_GRACE) );
|
||||
fd_psm_next_timeout(peer, 0, DPR_TIMEOUT);
|
||||
|
||||
/* Now send the DPR message */
|
||||
CHECK_FCT_DO( fd_out_send(&msg, NULL, peer, 0), /* ignore since we are on timeout anyway */ );
|
||||
|
||||
return 0;
|
||||
}
|
||||
177
plat/diameter/libfdcore/p_dw.c
Normal file
177
plat/diameter/libfdcore/p_dw.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
/* This file contains code to handle Device Watchdog messages (DWR and DWA) */
|
||||
|
||||
/* Check the value of Origin-State-Id is consistent in a DWR or DWA -- we return an error otherwise */
|
||||
static int check_state_id(struct msg * msg, struct fd_peer * peer)
|
||||
{
|
||||
struct avp * osi;
|
||||
|
||||
/* Check if the request contains the Origin-State-Id */
|
||||
CHECK_FCT( fd_msg_search_avp ( msg, fd_dict_avp_OSI, &osi ) );
|
||||
if (osi) {
|
||||
/* Check the value is consistent with the saved one */
|
||||
struct avp_hdr * hdr;
|
||||
CHECK_FCT( fd_msg_avp_hdr( osi, &hdr ) );
|
||||
if (hdr->avp_value == NULL) {
|
||||
/* This is a sanity check */
|
||||
LOG_F("Ignored an Origin-State-Id AVP with unset value in DWR/DWA");
|
||||
ASSERT(0); /* To check if this really happens, and understand why... */
|
||||
}
|
||||
|
||||
if (! peer->p_hdr.info.runtime.pir_orstate) {
|
||||
/* It was not already received in CER/CEA, save it now */
|
||||
peer->p_hdr.info.runtime.pir_orstate = hdr->avp_value->u32;
|
||||
}
|
||||
|
||||
if (peer->p_hdr.info.runtime.pir_orstate != hdr->avp_value->u32) {
|
||||
TRACE_DEBUG(INFO, "Received a new Origin-State-Id from peer '%s'! (%x -> %x); resetting the connection.",
|
||||
peer->p_hdr.info.pi_diamid,
|
||||
peer->p_hdr.info.runtime.pir_orstate,
|
||||
hdr->avp_value->u32 );
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create and send a DWR */
|
||||
static int send_DWR(struct fd_peer * peer)
|
||||
{
|
||||
struct msg * msg = NULL;
|
||||
|
||||
/* Create a new DWR instance */
|
||||
CHECK_FCT( fd_msg_new ( fd_dict_cmd_DWR, MSGFL_ALLOC_ETEID, &msg ) );
|
||||
|
||||
/* Add the content of the message (only the origin) */
|
||||
CHECK_FCT( fd_msg_add_origin ( msg, 1 ) );
|
||||
|
||||
/* Now send this message */
|
||||
CHECK_FCT( fd_out_send(&msg, NULL, peer, 0) );
|
||||
|
||||
/* And mark the pending DW */
|
||||
peer->p_flags.pf_dw_pending = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle an incoming message */
|
||||
int fd_p_dw_handle(struct msg ** msg, int req, struct fd_peer * peer)
|
||||
{
|
||||
int reset_tmr = 0;
|
||||
|
||||
TRACE_ENTRY("%p %d %p", msg, req, peer);
|
||||
|
||||
/* Check the value of OSI for information */
|
||||
CHECK_FCT( check_state_id(*msg, peer) );
|
||||
|
||||
if (req) {
|
||||
/* If we receive a DWR, send back a DWA */
|
||||
CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, 0 ) );
|
||||
CHECK_FCT( fd_msg_rescode_set( *msg, "DIAMETER_SUCCESS", NULL, NULL, 0 ) );
|
||||
CHECK_FCT( fd_msg_add_origin ( *msg, 1 ) );
|
||||
CHECK_FCT( fd_out_send( msg, peer->p_cnxctx, peer, 0) );
|
||||
|
||||
} else {
|
||||
/* Discard the DWA */
|
||||
CHECK_FCT_DO( fd_msg_free(*msg), /* continue */ );
|
||||
*msg = NULL;
|
||||
|
||||
/* And clear the pending DW flag */
|
||||
peer->p_flags.pf_dw_pending = 0;
|
||||
}
|
||||
|
||||
/* Now update timeout */
|
||||
if (req) {
|
||||
/* Update timeout only if we did not already send a DWR ourselves */
|
||||
reset_tmr = !peer->p_flags.pf_dw_pending;
|
||||
} else {
|
||||
/* Reset the timer */
|
||||
reset_tmr = 1;
|
||||
}
|
||||
if (reset_tmr) {
|
||||
fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw);
|
||||
}
|
||||
|
||||
/* If we are in REOPEN state, increment the counter */
|
||||
if (fd_peer_getstate(peer) == STATE_REOPEN) {
|
||||
peer->p_flags.pf_reopen_cnt += 1;
|
||||
|
||||
if (peer->p_flags.pf_reopen_cnt) {
|
||||
/* Send a new DWR */
|
||||
CHECK_FCT( send_DWR(peer) );
|
||||
} else {
|
||||
/* Move to OPEN state */
|
||||
CHECK_FCT( fd_psm_change_state(peer, STATE_OPEN) );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle a timeout in the PSM (OPEN or REOPEN state only) */
|
||||
int fd_p_dw_timeout(struct fd_peer * peer)
|
||||
{
|
||||
TRACE_ENTRY("%p", peer);
|
||||
|
||||
if (peer->p_flags.pf_dw_pending) {
|
||||
/* We have sent a DWR and received no answer during TwTimer */
|
||||
CHECK_FCT( fd_psm_change_state(peer, STATE_SUSPECT) );
|
||||
fd_psm_next_timeout(peer, 0, 2 * (peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw) );
|
||||
} else {
|
||||
/* The timeout has expired, send a DWR */
|
||||
CHECK_FCT( send_DWR(peer) );
|
||||
fd_psm_next_timeout(peer, 0, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle DW exchanges after the peer has come alive again */
|
||||
int fd_p_dw_reopen(struct fd_peer * peer)
|
||||
{
|
||||
TRACE_ENTRY("%p", peer);
|
||||
|
||||
peer->p_flags.pf_reopen_cnt = 1;
|
||||
peer->p_flags.pf_cnx_pb = 0;
|
||||
CHECK_FCT( send_DWR(peer) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
205
plat/diameter/libfdcore/p_expiry.c
Normal file
205
plat/diameter/libfdcore/p_expiry.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
/* Delay for garbage collection of expired peers, in seconds */
|
||||
#define GC_TIME 120
|
||||
|
||||
static pthread_t exp_thr = (pthread_t)NULL;
|
||||
static pthread_t gc_thr = (pthread_t)NULL;
|
||||
static struct fd_list exp_list = FD_LIST_INITIALIZER( exp_list );
|
||||
static pthread_cond_t exp_cnd = PTHREAD_COND_INITIALIZER;
|
||||
static pthread_mutex_t exp_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void * gc_th_fct(void * arg)
|
||||
{
|
||||
fd_log_threadname ( "Peers/garb. col." );
|
||||
TRACE_ENTRY( "%p", arg );
|
||||
|
||||
do {
|
||||
struct fd_list * li, purge = FD_LIST_INITIALIZER(purge);
|
||||
|
||||
sleep(GC_TIME); /* sleep is a cancellation point */
|
||||
|
||||
/* Now check in the peers list if any peer can be deleted */
|
||||
CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), goto error );
|
||||
|
||||
for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
|
||||
struct fd_peer * peer = (struct fd_peer *)li->o;
|
||||
|
||||
if (fd_peer_getstate(peer) != STATE_ZOMBIE)
|
||||
continue;
|
||||
|
||||
if (peer->p_hdr.info.config.pic_flags.persist == PI_PRST_ALWAYS)
|
||||
continue; /* This peer was not supposed to terminate, keep it in the list for debug */
|
||||
|
||||
/* Ok, the peer was expired, let's remove it */
|
||||
li = li->prev; /* to avoid breaking the loop */
|
||||
fd_list_unlink(&peer->p_hdr.chain);
|
||||
fd_list_insert_before(&purge, &peer->p_hdr.chain);
|
||||
}
|
||||
|
||||
CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), goto error );
|
||||
|
||||
/* Now delete peers that are in the purge list */
|
||||
while (!FD_IS_LIST_EMPTY(&purge)) {
|
||||
struct fd_peer * peer = (struct fd_peer *)(purge.next->o);
|
||||
fd_list_unlink(&peer->p_hdr.chain);
|
||||
TRACE_DEBUG(INFO, "Garbage Collect: delete zombie peer '%s'", peer->p_hdr.info.pi_diamid);
|
||||
CHECK_FCT_DO( fd_peer_free(&peer), /* Continue... what else to do ? */ );
|
||||
}
|
||||
} while (1);
|
||||
|
||||
error:
|
||||
TRACE_DEBUG(INFO, "An error occurred in peers module! GC thread is terminating...");
|
||||
ASSERT(0);
|
||||
CHECK_FCT_DO(fd_core_shutdown(), );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void * exp_th_fct(void * arg)
|
||||
{
|
||||
fd_log_threadname ( "Peers/expire" );
|
||||
TRACE_ENTRY( "%p", arg );
|
||||
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&exp_mtx), { ASSERT(0); } );
|
||||
pthread_cleanup_push( fd_cleanup_mutex, &exp_mtx );
|
||||
|
||||
do {
|
||||
struct timespec now;
|
||||
struct fd_peer * first;
|
||||
|
||||
/* Check if there are expiring peers available */
|
||||
if (FD_IS_LIST_EMPTY(&exp_list)) {
|
||||
/* Just wait for a change or cancelation */
|
||||
CHECK_POSIX_DO( pthread_cond_wait( &exp_cnd, &exp_mtx ), { ASSERT(0); } );
|
||||
/* Restart the loop on wakeup */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get the pointer to the peer that expires first */
|
||||
first = (struct fd_peer *)(exp_list.next->o);
|
||||
ASSERT( CHECK_PEER(first) );
|
||||
|
||||
/* Get the current time */
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), { ASSERT(0); } );
|
||||
|
||||
/* If first peer is not expired, we just wait until it happens */
|
||||
if ( TS_IS_INFERIOR( &now, &first->p_exp_timer ) ) {
|
||||
|
||||
CHECK_POSIX_DO2( pthread_cond_timedwait( &exp_cnd, &exp_mtx, &first->p_exp_timer ),
|
||||
ETIMEDOUT, /* ETIMEDOUT is a normal return value, continue */,
|
||||
/* on other error, */ { ASSERT(0); } );
|
||||
|
||||
/* on wakeup, loop */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now, the first peer in the list is expired; signal it */
|
||||
fd_list_unlink( &first->p_expiry );
|
||||
CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, 0, "DO_NOT_WANT_TO_TALK_TO_YOU"), break );
|
||||
|
||||
} while (1);
|
||||
|
||||
pthread_cleanup_pop( 1 );
|
||||
|
||||
TRACE_DEBUG(INFO, "An error occurred in peers module! Expiry thread is terminating...");
|
||||
CHECK_FCT_DO(fd_core_shutdown(), );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize peers expiry mechanism */
|
||||
int fd_p_expi_init(void)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
CHECK_FCT( pthread_create( &exp_thr, NULL, exp_th_fct, NULL ) );
|
||||
CHECK_FCT( pthread_create( &gc_thr, NULL, gc_th_fct, NULL ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Finish peers expiry mechanism */
|
||||
int fd_p_expi_fini(void)
|
||||
{
|
||||
CHECK_FCT_DO( fd_thr_term(&exp_thr), );
|
||||
CHECK_POSIX( pthread_mutex_lock(&exp_mtx) );
|
||||
while (!FD_IS_LIST_EMPTY(&exp_list)) {
|
||||
struct fd_peer * peer = (struct fd_peer *)(exp_list.next->o);
|
||||
fd_list_unlink(&peer->p_expiry );
|
||||
}
|
||||
CHECK_POSIX( pthread_mutex_unlock(&exp_mtx) );
|
||||
|
||||
CHECK_FCT_DO( fd_thr_term(&gc_thr), );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add / requeue a peer in the expiry list */
|
||||
int fd_p_expi_update(struct fd_peer * peer )
|
||||
{
|
||||
TRACE_ENTRY("%p", peer);
|
||||
CHECK_PARAMS( CHECK_PEER(peer) );
|
||||
|
||||
CHECK_POSIX( pthread_mutex_lock(&exp_mtx) );
|
||||
|
||||
fd_list_unlink(&peer->p_expiry );
|
||||
|
||||
/* if peer expires */
|
||||
if (peer->p_hdr.info.config.pic_flags.exp) {
|
||||
struct fd_list * li;
|
||||
|
||||
/* update the p_exp_timer value */
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &peer->p_exp_timer), { ASSERT(0); } );
|
||||
peer->p_exp_timer.tv_sec += peer->p_hdr.info.config.pic_lft;
|
||||
|
||||
/* add to the expiry list in appropriate position (probably around the end) */
|
||||
for (li = exp_list.prev; li != &exp_list; li = li->prev) {
|
||||
struct fd_peer * p = (struct fd_peer *)(li->o);
|
||||
if (TS_IS_INFERIOR( &p->p_exp_timer, &peer->p_exp_timer ) )
|
||||
break;
|
||||
}
|
||||
|
||||
fd_list_insert_after(li, &peer->p_expiry);
|
||||
|
||||
/* signal the expiry thread if we added in first position */
|
||||
if (li == &exp_list) {
|
||||
CHECK_POSIX( pthread_cond_signal(&exp_cnd) );
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_POSIX( pthread_mutex_unlock(&exp_mtx) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
237
plat/diameter/libfdcore/p_out.c
Normal file
237
plat/diameter/libfdcore/p_out.c
Normal file
@@ -0,0 +1,237 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
/* Alloc a new hbh for requests, bufferize the message and send on the connection, save in sentreq if provided */
|
||||
static int do_send(struct msg ** msg, struct cnxctx * cnx, uint32_t * hbh, struct fd_peer * peer)
|
||||
{
|
||||
struct msg_hdr * hdr;
|
||||
int msg_is_a_req;
|
||||
uint8_t * buf;
|
||||
size_t sz;
|
||||
int ret;
|
||||
uint32_t bkp_hbh = 0;
|
||||
struct msg *cpy_for_logs_only;
|
||||
|
||||
TRACE_ENTRY("%p %p %p %p", msg, cnx, hbh, peer);
|
||||
|
||||
/* Retrieve the message header */
|
||||
CHECK_FCT( fd_msg_hdr(*msg, &hdr) );
|
||||
|
||||
msg_is_a_req = (hdr->msg_flags & CMD_FLAG_REQUEST);
|
||||
if (msg_is_a_req) {
|
||||
CHECK_PARAMS(hbh && peer);
|
||||
/* Alloc the hop-by-hop id and increment the value for next message */
|
||||
bkp_hbh = hdr->msg_hbhid;
|
||||
hdr->msg_hbhid = *hbh;
|
||||
*hbh = hdr->msg_hbhid + 1;
|
||||
}
|
||||
|
||||
/* Create the message buffer */
|
||||
CHECK_FCT(fd_msg_bufferize( *msg, &buf, &sz ));
|
||||
pthread_cleanup_push( free, buf );
|
||||
|
||||
cpy_for_logs_only = *msg;
|
||||
|
||||
/* Save a request before sending so that there is no race condition with the answer */
|
||||
if (msg_is_a_req) {
|
||||
CHECK_FCT_DO( ret = fd_p_sr_store(&peer->p_sr, msg, &hdr->msg_hbhid, bkp_hbh), goto out );
|
||||
}
|
||||
|
||||
/* Log the message */
|
||||
fd_hook_call(HOOK_MESSAGE_SENT, cpy_for_logs_only, peer, NULL, fd_msg_pmdl_get(cpy_for_logs_only));
|
||||
|
||||
pthread_cleanup_push((void *)fd_msg_free, *msg /* might be NULL, no problem */);
|
||||
|
||||
/* Send the message */
|
||||
CHECK_FCT_DO( ret = fd_cnx_send(cnx, buf, sz), );
|
||||
|
||||
pthread_cleanup_pop(0);
|
||||
|
||||
out:
|
||||
;
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Free remaining messages (i.e. answers) */
|
||||
if (*msg) {
|
||||
CHECK_FCT( fd_msg_free(*msg) );
|
||||
*msg = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The code of the "out" thread */
|
||||
static void * out_thr(void * arg)
|
||||
{
|
||||
struct fd_peer * peer = arg;
|
||||
int stop = 0;
|
||||
struct msg * msg;
|
||||
ASSERT( CHECK_PEER(peer) );
|
||||
|
||||
/* Set the thread name */
|
||||
{
|
||||
char buf[48];
|
||||
snprintf(buf, sizeof(buf), "OUT/%s", peer->p_hdr.info.pi_diamid);
|
||||
fd_log_threadname ( buf );
|
||||
}
|
||||
|
||||
/* Loop until cancelation */
|
||||
while (!stop) {
|
||||
int ret;
|
||||
|
||||
/* Retrieve next message to send */
|
||||
CHECK_FCT_DO( fd_fifo_get(peer->p_tosend, &msg), goto error );
|
||||
|
||||
/* Send the message, log any error */
|
||||
CHECK_FCT_DO( ret = do_send(&msg, peer->p_cnxctx, &peer->p_hbh, peer),
|
||||
{
|
||||
if (msg) {
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "Error while sending this message: %s", strerror(ret));
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, msg, NULL, buf, fd_msg_pmdl_get(msg));
|
||||
fd_msg_free(msg);
|
||||
}
|
||||
stop = 1;
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
/* If we're here it means there was an error on the socket. We need to continue to purge the fifo & until we are canceled */
|
||||
CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL), /* What do we do if it fails? */ );
|
||||
|
||||
/* Requeue all routable messages in the global "out" queue, until we are canceled once the PSM deals with the CNX_ERROR sent above */
|
||||
while ( fd_fifo_get(peer->p_tosend, &msg) == 0 ) {
|
||||
if (fd_msg_is_routable(msg)) {
|
||||
CHECK_FCT_DO(fd_fifo_post_noblock(peer->p_tofailover, (void *)&msg),
|
||||
{
|
||||
/* fallback: destroy the message */
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, msg, NULL, "Internal error: unable to requeue this message during failover process", fd_msg_pmdl_get(msg));
|
||||
CHECK_FCT_DO(fd_msg_free(msg), /* What can we do more? */)
|
||||
} );
|
||||
} else {
|
||||
/* Just free it */
|
||||
/* fd_hook_call(HOOK_MESSAGE_DROPPED, m, NULL, "Non-routable message freed during handover", fd_msg_pmdl_get(m)); */
|
||||
CHECK_FCT_DO(fd_msg_free(msg), /* What can we do more? */)
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
/* It is not really a connection error, but the effect is the same, we are not able to send anymore message */
|
||||
CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL), /* What do we do if it fails? */ );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Wrapper to sending a message either by out thread (peer in OPEN state) or directly; cnx or peer must be provided. Flags are valid only for direct sending, not through thread (unused) */
|
||||
int fd_out_send(struct msg ** msg, struct cnxctx * cnx, struct fd_peer * peer, int update_reqin_cnt)
|
||||
{
|
||||
struct msg_hdr * hdr;
|
||||
|
||||
TRACE_ENTRY("%p %p %p", msg, cnx, peer);
|
||||
CHECK_PARAMS( msg && *msg && (cnx || (peer && peer->p_cnxctx)));
|
||||
|
||||
fd_hook_call(HOOK_MESSAGE_SENDING, *msg, peer, NULL, fd_msg_pmdl_get(*msg));
|
||||
|
||||
if (update_reqin_cnt && peer) {
|
||||
CHECK_FCT( fd_msg_hdr(*msg, &hdr) );
|
||||
if (!(hdr->msg_flags & CMD_FLAG_REQUEST)) {
|
||||
/* Update the count of pending answers to send */
|
||||
CHECK_POSIX( pthread_mutex_lock(&peer->p_state_mtx) );
|
||||
peer->p_reqin_count--;
|
||||
CHECK_POSIX( pthread_mutex_unlock(&peer->p_state_mtx) );
|
||||
}
|
||||
}
|
||||
|
||||
if (fd_peer_getstate(peer) == STATE_OPEN) {
|
||||
/* Normal case: just queue for the out thread to pick it up */
|
||||
CHECK_FCT( fd_fifo_post(peer->p_tosend, msg) );
|
||||
|
||||
} else {
|
||||
int ret;
|
||||
uint32_t *hbh = NULL;
|
||||
|
||||
/* In other cases, the thread is not running, so we handle the sending directly */
|
||||
if (peer)
|
||||
hbh = &peer->p_hbh;
|
||||
|
||||
if (!cnx)
|
||||
cnx = peer->p_cnxctx;
|
||||
|
||||
/* Do send the message */
|
||||
CHECK_FCT_DO( ret = do_send(msg, cnx, hbh, peer),
|
||||
{
|
||||
if (msg) {
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "Error while sending this message: %s", strerror(ret));
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, *msg, NULL, buf, fd_msg_pmdl_get(*msg));
|
||||
fd_msg_free(*msg);
|
||||
*msg = NULL;
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Start the "out" thread that picks messages in p_tosend and send them on p_cnxctx */
|
||||
int fd_out_start(struct fd_peer * peer)
|
||||
{
|
||||
TRACE_ENTRY("%p", peer);
|
||||
CHECK_PARAMS( CHECK_PEER(peer) && (peer->p_outthr == (pthread_t)NULL) );
|
||||
|
||||
CHECK_POSIX( pthread_create(&peer->p_outthr, NULL, out_thr, peer) );
|
||||
|
||||
CHECK_FCT( fd_cnx_unordered_delivery(peer->p_cnxctx, 1) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Stop that thread */
|
||||
int fd_out_stop(struct fd_peer * peer)
|
||||
{
|
||||
TRACE_ENTRY("%p", peer);
|
||||
CHECK_PARAMS( CHECK_PEER(peer) );
|
||||
|
||||
CHECK_FCT( fd_cnx_unordered_delivery(peer->p_cnxctx, 0) );
|
||||
|
||||
CHECK_FCT( fd_thr_term(&peer->p_outthr) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
958
plat/diameter/libfdcore/p_psm.c
Normal file
958
plat/diameter/libfdcore/p_psm.c
Normal file
@@ -0,0 +1,958 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
/*
|
||||
This file implement a Peer State Machine which is a mix of:
|
||||
- the state machine described in rfc3588bis
|
||||
- the state machine described in rfc3539#section-3.4
|
||||
- the following observations.
|
||||
|
||||
The delivery of Diameter messages must not always be unordered: order is important at
|
||||
begining and end of a connection lifetime. It means we need agility to
|
||||
switch between "ordering enforced" and "ordering not enforced to counter
|
||||
Head of the Line Blocking" modes of operation.
|
||||
|
||||
The connection state machine represented in RFC3588 (and RFC6733) is
|
||||
incomplete, because it lacks the SUSPECT state and the 3 DWR/DWA
|
||||
exchanges (section 5.1) when the peer recovers from this state.
|
||||
Personnally I don't see the rationale for exchanging 3 messages (why 3?)
|
||||
but, if we require at least 1 DWR/DWA exchange to be always performed
|
||||
after the CER/CEA exchange (and initiated by the peer that sent the
|
||||
CEA), we have a simple way to deal with our ordering problem, as resumed
|
||||
below. Peers are: [i]nitiator, [r]esponder.
|
||||
(1) [i] SCTP connection attempt.
|
||||
(2) [r] accept the connection.
|
||||
(3) [i,r] (if secure port) DTLS handshake, close on failure.
|
||||
(4) [i] Send CER
|
||||
(5) [r] Receive CER, send CEA using stream 0, flag "unordered" cleared.
|
||||
[r] Immediately send a DWR after the CEA, also using stream 0,
|
||||
flag "unordered" cleared.
|
||||
[r] Move to STATE_OPEN_NEW state -- equivalent to OPEN except
|
||||
that all messages are sent ordered at the moment.
|
||||
(6) [i] receive CEA, move to OPEN state. All messages can be sent
|
||||
unordered in OPEN state.
|
||||
[i] As per normal operation, reply with DWA to the DWR.
|
||||
(7) [r] Upon reception of the DWA, move to OPEN state, messages can be
|
||||
sent unordered from this point.
|
||||
|
||||
Note about (5) and (6): if the Diameter Identity received in CER or CEA
|
||||
does not match the credentials from the certificate presented during
|
||||
TLS handshake, we may need to specify a path of clean disconnection
|
||||
(not blocking the remote peer waiting for something).
|
||||
|
||||
This proposed mechanism removes the problem of application messages
|
||||
received before the CEA by the initiator. Note that if the "old" inband
|
||||
TLS handshake is used, this handshake plays the same synchronization
|
||||
role than the new DWR/DWA, which becomes useless.
|
||||
|
||||
|
||||
The other time where ordering is important is by the end of connection
|
||||
lifetime, when one peer is shutting down the link for some reason
|
||||
(reboot, overload, no activity, etc...). In case of unordered delivery,
|
||||
we may have:
|
||||
- peer A sends an application message followed by a DPR. Peer B receives
|
||||
the DPR first and tears down the connection. Application message is lost.
|
||||
- Peer B sends an application message, then receives a DPR and answers a
|
||||
DPA. Peer A receives the DPA before the application message. The
|
||||
application message is lost.
|
||||
|
||||
This situation is actually happening easily because DPR/DPA messages are
|
||||
very short, while application messages can be quite large. Therefore,
|
||||
they require much more time to deliver.
|
||||
|
||||
I really cannot see a way to counter this effect by using the ordering
|
||||
of the messages, except by applying a timer (state STATE_CLOSING_GRACE).
|
||||
This timer can be also useful when we detect that some messages has not
|
||||
yet received an answer on this link, to give time to the application to
|
||||
complete the exchange ongoing.
|
||||
|
||||
However, this problem must be balanced with the fact that the message
|
||||
that is lost will be in many cases sent again as the failover mechanism
|
||||
specifies.
|
||||
*/
|
||||
|
||||
/* The actual declaration of peer_state_str */
|
||||
DECLARE_STATE_STR();
|
||||
|
||||
/* Helper for next macro */
|
||||
#define case_str( _val ) \
|
||||
case _val : return #_val
|
||||
|
||||
DECLARE_PEV_STR();
|
||||
|
||||
/************************************************************************/
|
||||
/* Delayed startup */
|
||||
/************************************************************************/
|
||||
static int started = 0;
|
||||
static pthread_mutex_t started_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t started_cnd = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
/* Wait for start signal */
|
||||
static int fd_psm_waitstart()
|
||||
{
|
||||
int ret = 0;
|
||||
TRACE_ENTRY("");
|
||||
CHECK_POSIX( pthread_mutex_lock(&started_mtx) );
|
||||
awake:
|
||||
if (!ret && !started) {
|
||||
pthread_cleanup_push( fd_cleanup_mutex, &started_mtx );
|
||||
CHECK_POSIX_DO( ret = pthread_cond_wait(&started_cnd, &started_mtx), );
|
||||
pthread_cleanup_pop( 0 );
|
||||
goto awake;
|
||||
}
|
||||
CHECK_POSIX( pthread_mutex_unlock(&started_mtx) );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Allow the state machines to start */
|
||||
int fd_psm_start()
|
||||
{
|
||||
TRACE_ENTRY("");
|
||||
CHECK_POSIX( pthread_mutex_lock(&started_mtx) );
|
||||
started = 1;
|
||||
CHECK_POSIX( pthread_cond_broadcast(&started_cnd) );
|
||||
CHECK_POSIX( pthread_mutex_unlock(&started_mtx) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Manage the list of active peers */
|
||||
/************************************************************************/
|
||||
|
||||
/* Enter/leave OPEN state */
|
||||
static int enter_open_state(struct fd_peer * peer)
|
||||
{
|
||||
struct fd_list * li;
|
||||
CHECK_PARAMS( FD_IS_LIST_EMPTY(&peer->p_actives) );
|
||||
|
||||
/* Callback registered by the credential validator (fd_peer_validate_register) */
|
||||
if (peer->p_cb2) {
|
||||
CHECK_FCT_DO( (*peer->p_cb2)(&peer->p_hdr.info),
|
||||
{
|
||||
TRACE_DEBUG(FULL, "Validation failed, terminating the connection");
|
||||
fd_psm_terminate(peer, "DO_NOT_WANT_TO_TALK_TO_YOU" );
|
||||
} );
|
||||
peer->p_cb2 = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Insert in the active peers list */
|
||||
CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_activ_peers_rw) );
|
||||
for (li = fd_g_activ_peers.next; li != &fd_g_activ_peers; li = li->next) {
|
||||
struct fd_peer * next_p = (struct fd_peer *)li->o;
|
||||
int cmp = fd_os_cmp(peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen,
|
||||
next_p->p_hdr.info.pi_diamid, next_p->p_hdr.info.pi_diamidlen);
|
||||
if (cmp < 0)
|
||||
break;
|
||||
}
|
||||
fd_list_insert_before(li, &peer->p_actives);
|
||||
CHECK_POSIX( pthread_rwlock_unlock(&fd_g_activ_peers_rw) );
|
||||
|
||||
/* Callback registered when the peer was added, by fd_peer_add */
|
||||
if (peer->p_cb) {
|
||||
LOG_N("Calling add callback for peer %s", peer->p_hdr.info.pi_diamid);
|
||||
(*peer->p_cb)(&peer->p_hdr.info, peer->p_cb_data); /* TODO: do this in a separate detached thread? */
|
||||
// peer->p_cb = NULL;
|
||||
// peer->p_cb_data = NULL;
|
||||
}
|
||||
|
||||
/* Start the thread to handle outgoing messages */
|
||||
CHECK_FCT( fd_out_start(peer) );
|
||||
|
||||
/* Update the expiry timer now */
|
||||
CHECK_FCT( fd_p_expi_update(peer) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int leave_open_state(struct fd_peer * peer, int skip_failover)
|
||||
{
|
||||
/* Remove from active peers list */
|
||||
CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_activ_peers_rw) );
|
||||
fd_list_unlink( &peer->p_actives );
|
||||
CHECK_POSIX( pthread_rwlock_unlock(&fd_g_activ_peers_rw) );
|
||||
|
||||
/* Stop the "out" thread */
|
||||
CHECK_FCT( fd_out_stop(peer) );
|
||||
|
||||
/* Failover the messages */
|
||||
if (!skip_failover) {
|
||||
fd_peer_failover_msg(peer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Helpers for state changes */
|
||||
/************************************************************************/
|
||||
|
||||
/* Cleanup pending events in the peer */
|
||||
void fd_psm_events_free(struct fd_peer * peer)
|
||||
{
|
||||
struct fd_event * ev;
|
||||
/* Purge all events, and free the associated data if any */
|
||||
while (fd_fifo_tryget( peer->p_events, &ev ) == 0) {
|
||||
switch (ev->code) {
|
||||
case FDEVP_CNX_ESTABLISHED: {
|
||||
fd_cnx_destroy(ev->data);
|
||||
}
|
||||
break;
|
||||
|
||||
case FDEVP_TERMINATE:
|
||||
/* Do not free the string since it is a constant */
|
||||
break;
|
||||
|
||||
case FDEVP_CNX_INCOMING: {
|
||||
struct cnx_incoming * evd = ev->data;
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, evd->cer, NULL, "Message discarded while cleaning peer state machine queue.", fd_msg_pmdl_get(evd->cer));
|
||||
CHECK_FCT_DO( fd_msg_free(evd->cer), /* continue */);
|
||||
fd_cnx_destroy(evd->cnx);
|
||||
}
|
||||
default:
|
||||
free(ev->data);
|
||||
}
|
||||
free(ev);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read state */
|
||||
int fd_peer_get_state(struct peer_hdr *peer)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct fd_peer * p = (struct fd_peer *)peer;
|
||||
|
||||
if (!CHECK_PEER(p))
|
||||
return -1;
|
||||
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&p->p_state_mtx), return -1 );
|
||||
ret = p->p_state;
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&p->p_state_mtx), return -1 );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Change state */
|
||||
int fd_psm_change_state(struct fd_peer * peer, int new_state)
|
||||
{
|
||||
int old;
|
||||
|
||||
TRACE_ENTRY("%p %d(%s)", peer, new_state, STATE_STR(new_state));
|
||||
CHECK_PARAMS( CHECK_PEER(peer) );
|
||||
|
||||
old = fd_peer_getstate(peer);
|
||||
if (old == new_state)
|
||||
return 0;
|
||||
|
||||
LOG(((old == STATE_OPEN) || (new_state == STATE_OPEN)) ? FD_LOG_NOTICE : FD_LOG_DEBUG, "'%s'\t-> '%s'\t'%s'",
|
||||
STATE_STR(old),
|
||||
STATE_STR(new_state),
|
||||
peer->p_hdr.info.pi_diamid);
|
||||
|
||||
|
||||
CHECK_POSIX( pthread_mutex_lock(&peer->p_state_mtx) );
|
||||
peer->p_state = new_state;
|
||||
CHECK_POSIX( pthread_mutex_unlock(&peer->p_state_mtx) );
|
||||
|
||||
if (old == STATE_OPEN) {
|
||||
CHECK_FCT( leave_open_state(peer, new_state == STATE_CLOSING_GRACE) );
|
||||
}
|
||||
if (old == STATE_CLOSING_GRACE) {
|
||||
fd_peer_failover_msg(peer);
|
||||
}
|
||||
|
||||
if (new_state == STATE_OPEN) {
|
||||
CHECK_FCT( enter_open_state(peer) );
|
||||
}
|
||||
|
||||
if (new_state == STATE_CLOSED) {
|
||||
/* Purge event list */
|
||||
fd_psm_events_free(peer);
|
||||
|
||||
/* Reset the counter of pending anwers to send */
|
||||
peer->p_reqin_count = 0;
|
||||
|
||||
/* If the peer is not persistant, we destroy it */
|
||||
if (peer->p_hdr.info.config.pic_flags.persist == PI_PRST_NONE) {
|
||||
CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set timeout timer of next event */
|
||||
void fd_psm_next_timeout(struct fd_peer * peer, int add_random, int delay)
|
||||
{
|
||||
TRACE_DEBUG(FULL, "Peer timeout reset to %d seconds%s", delay, add_random ? " (+/- 2)" : "" );
|
||||
|
||||
/* Initialize the timer */
|
||||
CHECK_POSIX_DO( clock_gettime( CLOCK_REALTIME, &peer->p_psm_timer ), ASSERT(0) );
|
||||
|
||||
if (add_random) {
|
||||
if (delay > 2)
|
||||
delay -= 2;
|
||||
else
|
||||
delay = 0;
|
||||
|
||||
/* Add a random value between 0 and 4sec */
|
||||
peer->p_psm_timer.tv_sec += random() % 4;
|
||||
peer->p_psm_timer.tv_nsec+= random() % 1000000000L;
|
||||
if (peer->p_psm_timer.tv_nsec >= 1000000000L) {
|
||||
peer->p_psm_timer.tv_nsec -= 1000000000L;
|
||||
peer->p_psm_timer.tv_sec ++;
|
||||
}
|
||||
}
|
||||
|
||||
peer->p_psm_timer.tv_sec += delay;
|
||||
|
||||
#ifdef SLOW_PSM
|
||||
/* temporary for debug */
|
||||
peer->p_psm_timer.tv_sec += 10;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Cleanup the peer */
|
||||
void fd_psm_cleanup(struct fd_peer * peer, int terminate)
|
||||
{
|
||||
/* Move to CLOSED state: failover messages, stop OUT thread, unlink peer from active list */
|
||||
if (fd_peer_getstate(peer) != STATE_ZOMBIE) {
|
||||
CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), /* continue */ );
|
||||
}
|
||||
|
||||
fd_p_cnx_abort(peer, terminate);
|
||||
|
||||
fd_p_ce_clear_cnx(peer, NULL);
|
||||
|
||||
if (peer->p_receiver) {
|
||||
fd_cnx_destroy(peer->p_receiver);
|
||||
peer->p_receiver = NULL;
|
||||
}
|
||||
|
||||
if (terminate) {
|
||||
fd_psm_events_free(peer);
|
||||
CHECK_FCT_DO( fd_fifo_del(&peer->p_events), /* continue */ );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* The PSM thread */
|
||||
/************************************************************************/
|
||||
/* Cancelation cleanup : set ZOMBIE state in the peer */
|
||||
void cleanup_setstate(void * arg)
|
||||
{
|
||||
struct fd_peer * peer = (struct fd_peer *)arg;
|
||||
CHECK_PARAMS_DO( CHECK_PEER(peer), return );
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&peer->p_state_mtx), );
|
||||
peer->p_state = STATE_ZOMBIE;
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&peer->p_state_mtx), );
|
||||
return;
|
||||
}
|
||||
|
||||
/* The state machine thread (controler) */
|
||||
static void * p_psm_th( void * arg )
|
||||
{
|
||||
struct fd_peer * peer = (struct fd_peer *)arg;
|
||||
int created_started = started ? 1 : 0;
|
||||
int event;
|
||||
size_t ev_sz;
|
||||
void * ev_data;
|
||||
int cur_state;
|
||||
|
||||
CHECK_PARAMS_DO( CHECK_PEER(peer), ASSERT(0) );
|
||||
|
||||
pthread_cleanup_push( cleanup_setstate, arg );
|
||||
|
||||
/* Set the thread name */
|
||||
{
|
||||
char buf[48];
|
||||
snprintf(buf, sizeof(buf), "PSM/%s", peer->p_hdr.info.pi_diamid);
|
||||
fd_log_threadname ( buf );
|
||||
}
|
||||
|
||||
/* The state machine starts in CLOSED state */
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&peer->p_state_mtx), goto psm_end );
|
||||
peer->p_state = STATE_CLOSED;
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&peer->p_state_mtx), goto psm_end );
|
||||
|
||||
/* Wait that the PSM are authorized to start in the daemon */
|
||||
CHECK_FCT_DO( fd_psm_waitstart(), goto psm_end );
|
||||
|
||||
/* Initialize the timer */
|
||||
if (peer->p_flags.pf_responder) {
|
||||
fd_psm_next_timeout(peer, 0, INCNX_TIMEOUT);
|
||||
} else {
|
||||
fd_psm_next_timeout(peer, created_started, 0);
|
||||
}
|
||||
|
||||
psm_loop:
|
||||
/* Get next event */
|
||||
TRACE_DEBUG(FULL, "'%s' in state '%s' waiting for next event.",
|
||||
peer->p_hdr.info.pi_diamid, STATE_STR(fd_peer_getstate(peer)));
|
||||
CHECK_FCT_DO( fd_event_timedget(peer->p_events, &peer->p_psm_timer, FDEVP_PSM_TIMEOUT, &event, &ev_sz, &ev_data), goto psm_end );
|
||||
|
||||
cur_state = fd_peer_getstate(peer);
|
||||
if (cur_state == -1)
|
||||
goto psm_end;
|
||||
|
||||
TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p,%zd)\t'%s'",
|
||||
STATE_STR(cur_state),
|
||||
fd_pev_str(event), ev_data, ev_sz,
|
||||
peer->p_hdr.info.pi_diamid);
|
||||
|
||||
/* Now, the action depends on the current state and the incoming event */
|
||||
|
||||
/* The following states are impossible */
|
||||
ASSERT( cur_state != STATE_NEW );
|
||||
ASSERT( cur_state != STATE_ZOMBIE );
|
||||
ASSERT( cur_state != STATE_OPEN_HANDSHAKE ); /* because it should exist only between two loops */
|
||||
|
||||
/* Purge invalid events */
|
||||
if (!CHECK_PEVENT(event)) {
|
||||
TRACE_DEBUG(INFO, "Invalid event received in PSM '%s' : %d", peer->p_hdr.info.pi_diamid, event);
|
||||
ASSERT(0); /* we should investigate this situation */
|
||||
goto psm_loop;
|
||||
}
|
||||
|
||||
/* Requests to terminate the peer object */
|
||||
if (event == FDEVP_TERMINATE) {
|
||||
switch (cur_state) {
|
||||
case STATE_OPEN:
|
||||
case STATE_OPEN_NEW:
|
||||
case STATE_REOPEN:
|
||||
/* We cannot just close the connection, we have to send a DPR first */
|
||||
CHECK_FCT_DO( fd_p_dp_initiate(peer, ev_data), goto psm_end );
|
||||
goto psm_loop;
|
||||
|
||||
/*
|
||||
case STATE_CLOSING:
|
||||
case STATE_CLOSING_GRACE:
|
||||
case STATE_WAITCNXACK:
|
||||
case STATE_WAITCNXACK_ELEC:
|
||||
case STATE_WAITCEA:
|
||||
case STATE_SUSPECT:
|
||||
case STATE_CLOSED:
|
||||
*/
|
||||
default:
|
||||
/* In these cases, we just cleanup the peer object (if needed) and terminate */
|
||||
goto psm_end;
|
||||
}
|
||||
}
|
||||
|
||||
/* A message was received */
|
||||
if (event == FDEVP_CNX_MSG_RECV) {
|
||||
struct msg * msg = NULL;
|
||||
struct msg_hdr * hdr;
|
||||
struct fd_cnx_rcvdata rcv_data;
|
||||
struct fd_msg_pmdl * pmdl = NULL;
|
||||
|
||||
rcv_data.buffer = ev_data;
|
||||
rcv_data.length = ev_sz;
|
||||
pmdl = fd_msg_pmdl_get_inbuf(rcv_data.buffer, rcv_data.length);
|
||||
|
||||
/* Parse the received buffer */
|
||||
CHECK_FCT_DO( fd_msg_parse_buffer( (void *)&ev_data, ev_sz, &msg),
|
||||
{
|
||||
fd_hook_call(HOOK_MESSAGE_PARSING_ERROR, NULL, peer, &rcv_data, pmdl );
|
||||
free(ev_data);
|
||||
CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL), goto psm_reset );
|
||||
goto psm_loop;
|
||||
} );
|
||||
|
||||
fd_hook_associate(msg, pmdl);
|
||||
CHECK_FCT_DO( fd_msg_source_set( msg, peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen), goto psm_end);
|
||||
|
||||
/* If the current state does not allow receiving messages, just drop it */
|
||||
if (cur_state == STATE_CLOSED) {
|
||||
/* In such case, just discard the message */
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, msg, peer, "Message purged from queue, peer in CLOSED state", fd_msg_pmdl_get(msg));
|
||||
fd_msg_free(msg);
|
||||
goto psm_loop;
|
||||
}
|
||||
|
||||
/* Extract the header */
|
||||
CHECK_FCT_DO( fd_msg_hdr(msg, &hdr), goto psm_end );
|
||||
|
||||
/* If it is an answer, associate with the request or drop */
|
||||
if (!(hdr->msg_flags & CMD_FLAG_REQUEST)) {
|
||||
struct msg * req;
|
||||
/* Search matching request (same hbhid) */
|
||||
CHECK_FCT_DO( fd_p_sr_fetch(&peer->p_sr, hdr->msg_hbhid, &req), goto psm_end );
|
||||
if (req == NULL) {
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, msg, peer, "Answer received with no corresponding sent request.", fd_msg_pmdl_get(msg));
|
||||
fd_msg_free(msg);
|
||||
goto psm_loop;
|
||||
}
|
||||
|
||||
/* Associate */
|
||||
CHECK_FCT_DO( fd_msg_answ_associate( msg, req ), goto psm_end );
|
||||
|
||||
}
|
||||
|
||||
/* Log incoming message */
|
||||
fd_hook_call(HOOK_MESSAGE_RECEIVED, msg, peer, NULL, fd_msg_pmdl_get(msg));
|
||||
|
||||
if (cur_state == STATE_OPEN_NEW) {
|
||||
/* OK, we have received something, so the connection is supposedly now in OPEN state at the remote site */
|
||||
fd_psm_change_state(peer, STATE_OPEN );
|
||||
}
|
||||
|
||||
/* Now handle non-link-local messages */
|
||||
if (fd_msg_is_routable(msg)) {
|
||||
switch (cur_state) {
|
||||
/* To maximize compatibility -- should not be a security issue here */
|
||||
case STATE_REOPEN:
|
||||
case STATE_SUSPECT:
|
||||
case STATE_CLOSING:
|
||||
case STATE_CLOSING_GRACE:
|
||||
TRACE_DEBUG(FULL, "Accepted a message while not in OPEN state... ");
|
||||
/* The standard situation : */
|
||||
case STATE_OPEN_NEW:
|
||||
case STATE_OPEN:
|
||||
/* We received a valid routable message, update the expiry timer */
|
||||
CHECK_FCT_DO( fd_p_expi_update(peer), goto psm_end );
|
||||
|
||||
/* Set the message source and add the Route-Record */
|
||||
CHECK_FCT_DO( fd_msg_source_setrr( msg, peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen, fd_g_config->cnf_dict ), goto psm_end);
|
||||
|
||||
if ((hdr->msg_flags & CMD_FLAG_REQUEST)) {
|
||||
/* Mark the incoming request so that we know we have pending answers for this peer */
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&peer->p_state_mtx), goto psm_end );
|
||||
peer->p_reqin_count++;
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&peer->p_state_mtx), goto psm_end );
|
||||
}
|
||||
|
||||
/* Requeue to the global incoming queue */
|
||||
CHECK_FCT_DO(fd_fifo_post(fd_g_incoming, &msg), goto psm_end );
|
||||
|
||||
/* Update the peer timer (only in OPEN state) */
|
||||
if ((cur_state == STATE_OPEN) && (!peer->p_flags.pf_dw_pending)) {
|
||||
fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw);
|
||||
}
|
||||
break;
|
||||
|
||||
/* In other states, we discard the message, it is either old or invalid to send it for the remote peer */
|
||||
case STATE_WAITCNXACK:
|
||||
case STATE_WAITCNXACK_ELEC:
|
||||
case STATE_WAITCEA:
|
||||
case STATE_CLOSED:
|
||||
default: {
|
||||
/* In such case, just discard the message */
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "Received while peer state machine was in state %s.", STATE_STR(cur_state));
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, msg, peer, buf, fd_msg_pmdl_get(msg));
|
||||
fd_msg_free(msg);
|
||||
}
|
||||
}
|
||||
goto psm_loop;
|
||||
}
|
||||
|
||||
/* Link-local message: They must be understood by our dictionary, otherwise we return an error */
|
||||
{
|
||||
struct msg * error = NULL;
|
||||
int ret = fd_msg_parse_or_error( &msg, &error );
|
||||
if (ret != EBADMSG) {
|
||||
CHECK_FCT_DO( ret,
|
||||
{
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "%s: An unexpected error occurred while parsing a link-local message", peer->p_hdr.info.pi_diamid);
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, msg, peer, buf, fd_msg_pmdl_get(msg));
|
||||
fd_msg_free(msg);
|
||||
goto psm_end;
|
||||
} );
|
||||
} else {
|
||||
if (msg == NULL) {
|
||||
/* Send the error back to the peer */
|
||||
CHECK_FCT_DO( ret = fd_out_send(&error, NULL, peer, 0), );
|
||||
if (error) {
|
||||
char buf[256];
|
||||
/* Only if an error occurred & the message was not saved / dumped */
|
||||
snprintf(buf, sizeof(buf), "%s: error sending a message", peer->p_hdr.info.pi_diamid);
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, error, peer, buf, fd_msg_pmdl_get(error));
|
||||
CHECK_FCT_DO( fd_msg_free(error), goto psm_end);
|
||||
}
|
||||
} else {
|
||||
char buf[256];
|
||||
/* We received an invalid answer, let's disconnect */
|
||||
snprintf(buf, sizeof(buf), "%s: Received invalid answer to Base protocol message, disconnecting...", peer->p_hdr.info.pi_diamid);
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, msg, peer, buf, fd_msg_pmdl_get(msg));
|
||||
CHECK_FCT_DO( fd_msg_free(msg), goto psm_end);
|
||||
CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL), goto psm_reset );
|
||||
}
|
||||
goto psm_loop;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle the LL message and update the expiry timer appropriately */
|
||||
switch (hdr->msg_code) {
|
||||
case CC_CAPABILITIES_EXCHANGE:
|
||||
CHECK_FCT_DO( fd_p_ce_msgrcv(&msg, (hdr->msg_flags & CMD_FLAG_REQUEST), peer),
|
||||
{
|
||||
if (msg)
|
||||
CHECK_FCT_DO( fd_msg_free(msg), );
|
||||
goto psm_reset;
|
||||
} );
|
||||
break;
|
||||
|
||||
case CC_DISCONNECT_PEER:
|
||||
CHECK_FCT_DO( fd_p_dp_handle(&msg, (hdr->msg_flags & CMD_FLAG_REQUEST), peer), goto psm_reset );
|
||||
if (fd_peer_getstate(peer) == STATE_CLOSING)
|
||||
goto psm_end;
|
||||
|
||||
break;
|
||||
|
||||
case CC_DEVICE_WATCHDOG:
|
||||
/* We received a WDA message, update the expiry timer */
|
||||
if (!(hdr->msg_flags & CMD_FLAG_REQUEST))
|
||||
{
|
||||
fd_p_expi_update(peer);
|
||||
}
|
||||
|
||||
CHECK_FCT_DO( fd_p_dw_handle(&msg, (hdr->msg_flags & CMD_FLAG_REQUEST), peer), goto psm_reset );
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Unknown / unexpected / invalid message -- but validated by our dictionary */
|
||||
TRACE_DEBUG(INFO, "Invalid non-routable command received: %u.", hdr->msg_code);
|
||||
if (hdr->msg_flags & CMD_FLAG_REQUEST) {
|
||||
do {
|
||||
/* Reply with an error code */
|
||||
CHECK_FCT_DO( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &msg, MSGFL_ANSW_ERROR ), break );
|
||||
|
||||
/* Set the error code */
|
||||
CHECK_FCT_DO( fd_msg_rescode_set(msg, "DIAMETER_COMMAND_UNSUPPORTED", "Or maybe the P-bit or application Id are erroneous.", NULL, 1 ), break );
|
||||
|
||||
/* Send the answer */
|
||||
CHECK_FCT_DO( fd_out_send(&msg, peer->p_cnxctx, peer, 0), break );
|
||||
} while (0);
|
||||
} else {
|
||||
/* We did ASK for it ??? */
|
||||
TRACE_DEBUG(INFO, "Received answer with erroneous 'is_routable' result...");
|
||||
}
|
||||
|
||||
/* Cleanup the message if not done */
|
||||
if (msg) {
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "Received un-handled non-routable command from peer '%s'.", peer->p_hdr.info.pi_diamid);
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, msg, NULL, buf, fd_msg_pmdl_get(msg));
|
||||
CHECK_FCT_DO( fd_msg_free(msg), /* continue */);
|
||||
msg = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
/* At this point the message must have been fully handled already */
|
||||
if (msg) {
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "Internal error ('%s'): unhandled message.", peer->p_hdr.info.pi_diamid);
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, msg, NULL, buf, fd_msg_pmdl_get(msg));
|
||||
fd_msg_free(msg);
|
||||
}
|
||||
|
||||
goto psm_loop;
|
||||
}
|
||||
|
||||
/* The connection object is broken */
|
||||
if (event == FDEVP_CNX_ERROR) {
|
||||
switch (cur_state) {
|
||||
case STATE_WAITCNXACK_ELEC:
|
||||
/* Abort the initiating side */
|
||||
fd_p_cnx_abort(peer, 0);
|
||||
/* Process the receiver side */
|
||||
CHECK_FCT_DO( fd_p_ce_process_receiver(peer), goto psm_end );
|
||||
break;
|
||||
|
||||
case STATE_WAITCEA:
|
||||
case STATE_OPEN:
|
||||
case STATE_OPEN_NEW:
|
||||
case STATE_REOPEN:
|
||||
case STATE_WAITCNXACK:
|
||||
case STATE_SUSPECT:
|
||||
default:
|
||||
/* Mark the connection problem */
|
||||
peer->p_flags.pf_cnx_pb = 1;
|
||||
|
||||
fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, peer, "The connection was broken", NULL);
|
||||
|
||||
/* Destroy the connection, restart the timer to a new connection attempt */
|
||||
fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc);
|
||||
|
||||
case STATE_CLOSED:
|
||||
goto psm_reset;
|
||||
|
||||
case STATE_CLOSING:
|
||||
/* We sent a DPR so we are terminating, do not wait for DPA */
|
||||
goto psm_end;
|
||||
|
||||
case STATE_CLOSING_GRACE:
|
||||
if (peer->p_flags.pf_localterm) /* initiated here */
|
||||
goto psm_end;
|
||||
|
||||
fd_psm_cleanup(peer, 0);
|
||||
|
||||
/* Reset the timer for next connection attempt */
|
||||
fd_psm_next_timeout(peer, 1, fd_p_dp_newdelay(peer));
|
||||
goto psm_loop;
|
||||
}
|
||||
goto psm_loop;
|
||||
}
|
||||
|
||||
/* The connection notified a change in endpoints */
|
||||
if (event == FDEVP_CNX_EP_CHANGE) {
|
||||
/* We actually don't care if we are in OPEN state here... */
|
||||
|
||||
/* Cleanup the remote LL and primary addresses */
|
||||
CHECK_FCT_DO( fd_ep_filter( &peer->p_hdr.info.pi_endpoints, EP_FL_CONF | EP_FL_DISC | EP_FL_ADV ), /* ignore the error */);
|
||||
CHECK_FCT_DO( fd_ep_clearflags( &peer->p_hdr.info.pi_endpoints, EP_FL_PRIMARY ), /* ignore the error */);
|
||||
|
||||
/* Get the new ones */
|
||||
CHECK_FCT_DO( fd_cnx_getremoteeps(peer->p_cnxctx, &peer->p_hdr.info.pi_endpoints), /* ignore the error */);
|
||||
|
||||
/* We do not support local endpoints change currently, but it could be added here if needed (refresh fd_g_config->cnf_endpoints) */
|
||||
{
|
||||
char * buf = NULL;
|
||||
size_t len = 0;
|
||||
LOG_D("Got low layer notification (IGNORED): remote endpoint(s) changed: %s", fd_ep_dump(&buf, &len, NULL, 0, 0, &peer->p_hdr.info.pi_endpoints) ?: "error");
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/* Done */
|
||||
goto psm_loop;
|
||||
}
|
||||
|
||||
/* A new connection was established and CER containing this peer id was received */
|
||||
if (event == FDEVP_CNX_INCOMING) {
|
||||
struct cnx_incoming * params = ev_data;
|
||||
ASSERT(params);
|
||||
|
||||
/* Handle the message */
|
||||
CHECK_FCT_DO( fd_p_ce_handle_newCER(¶ms->cer, peer, ¶ms->cnx, params->validate), goto psm_end );
|
||||
|
||||
/* Cleanup if needed */
|
||||
if (params->cnx) {
|
||||
fd_cnx_destroy(params->cnx);
|
||||
params->cnx = NULL;
|
||||
}
|
||||
if (params->cer) {
|
||||
CHECK_FCT_DO( fd_msg_free(params->cer), );
|
||||
params->cer = NULL;
|
||||
}
|
||||
|
||||
/* Loop */
|
||||
free(ev_data);
|
||||
goto psm_loop;
|
||||
}
|
||||
|
||||
/* A new connection has been established with the remote peer */
|
||||
if (event == FDEVP_CNX_ESTABLISHED) {
|
||||
struct cnxctx * cnx = ev_data;
|
||||
|
||||
/* Release the resources of the connecting thread */
|
||||
CHECK_POSIX_DO( pthread_join( peer->p_ini_thr, NULL), /* ignore, it is not a big deal */);
|
||||
peer->p_ini_thr = (pthread_t)NULL;
|
||||
|
||||
switch (cur_state) {
|
||||
case STATE_WAITCNXACK_ELEC:
|
||||
case STATE_WAITCNXACK:
|
||||
LOG_D("%s: Connection established, %s", peer->p_hdr.info.pi_diamid, fd_cnx_getid(cnx));
|
||||
fd_p_ce_handle_newcnx(peer, cnx);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Just abort the attempt and continue */
|
||||
TRACE_DEBUG(FULL, "Connection attempt successful but current state is %s, closing... (too slow?)", STATE_STR(cur_state));
|
||||
fd_cnx_destroy(cnx);
|
||||
}
|
||||
|
||||
goto psm_loop;
|
||||
}
|
||||
|
||||
/* A new connection has not been established with the remote peer */
|
||||
if (event == FDEVP_CNX_FAILED) {
|
||||
|
||||
/* Release the resources of the connecting thread */
|
||||
CHECK_POSIX_DO( pthread_join( peer->p_ini_thr, NULL), /* ignore, it is not a big deal */);
|
||||
peer->p_ini_thr = (pthread_t)NULL;
|
||||
|
||||
switch (cur_state) {
|
||||
case STATE_WAITCNXACK_ELEC:
|
||||
/* Abort the initiating side */
|
||||
fd_p_cnx_abort(peer, 0);
|
||||
/* Process the receiver side */
|
||||
CHECK_FCT_DO( fd_p_ce_process_receiver(peer), goto psm_end );
|
||||
break;
|
||||
|
||||
case STATE_WAITCNXACK:
|
||||
/* Go back to CLOSE */
|
||||
fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc);
|
||||
goto psm_reset;
|
||||
|
||||
default:
|
||||
/* Just ignore */
|
||||
TRACE_DEBUG(FULL, "Connection attempt failed but current state is %s, ignoring...", STATE_STR(cur_state));
|
||||
}
|
||||
|
||||
goto psm_loop;
|
||||
}
|
||||
|
||||
/* The timeout for the current state has been reached */
|
||||
if (event == FDEVP_PSM_TIMEOUT) {
|
||||
switch (cur_state) {
|
||||
case STATE_OPEN:
|
||||
case STATE_REOPEN:
|
||||
case STATE_OPEN_NEW:
|
||||
CHECK_FCT_DO( fd_p_dw_timeout(peer), goto psm_end );
|
||||
goto psm_loop;
|
||||
|
||||
case STATE_CLOSED:
|
||||
LOG_D("%s: Connecting...", peer->p_hdr.info.pi_diamid);
|
||||
CHECK_FCT_DO( fd_psm_change_state(peer, STATE_WAITCNXACK), goto psm_end );
|
||||
fd_psm_next_timeout(peer, 0, CNX_TIMEOUT);
|
||||
CHECK_FCT_DO( fd_p_cnx_init(peer), goto psm_end );
|
||||
goto psm_loop;
|
||||
|
||||
case STATE_SUSPECT:
|
||||
/* Mark the connection problem */
|
||||
peer->p_flags.pf_cnx_pb = 1;
|
||||
case STATE_WAITCNXACK:
|
||||
case STATE_WAITCEA:
|
||||
fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, peer, "Timeout while waiting for remote peer", NULL);
|
||||
case STATE_CLOSING:
|
||||
/* Destroy the connection, restart the timer to a new connection attempt */
|
||||
fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc);
|
||||
goto psm_reset;
|
||||
|
||||
case STATE_CLOSING_GRACE:
|
||||
/* The grace period is completed, now close */
|
||||
if (peer->p_flags.pf_localterm)
|
||||
goto psm_end;
|
||||
|
||||
fd_psm_cleanup(peer, 0);
|
||||
/* Reset the timer for next connection attempt */
|
||||
fd_psm_next_timeout(peer, 1, fd_p_dp_newdelay(peer));
|
||||
goto psm_loop;
|
||||
|
||||
case STATE_WAITCNXACK_ELEC:
|
||||
/* Abort the initiating side */
|
||||
fd_p_cnx_abort(peer, 0);
|
||||
/* Process the receiver side */
|
||||
CHECK_FCT_DO( fd_p_ce_process_receiver(peer), goto psm_end );
|
||||
goto psm_loop;
|
||||
|
||||
default:
|
||||
ASSERT(0); /* implementation problem, we did not foresee this case? */
|
||||
}
|
||||
}
|
||||
|
||||
/* Default action : the handling has not yet been implemented. [for debug only] */
|
||||
TRACE_DEBUG(INFO, "Missing handler in PSM for '%s'\t<-- '%s'", STATE_STR(cur_state), fd_pev_str(event));
|
||||
psm_reset:
|
||||
if (peer->p_flags.pf_delete)
|
||||
goto psm_end;
|
||||
fd_psm_cleanup(peer, 0);
|
||||
goto psm_loop;
|
||||
|
||||
psm_end:
|
||||
LOG_N("%s: Going to ZOMBIE state (no more activity)", peer->p_hdr.info.pi_diamid);
|
||||
fd_psm_cleanup(peer, 1);
|
||||
TRACE_DEBUG(INFO, "'%s'\t-> STATE_ZOMBIE (terminated)\t'%s'",
|
||||
STATE_STR(fd_peer_getstate(peer)),
|
||||
peer->p_hdr.info.pi_diamid);
|
||||
pthread_cleanup_pop(1); /* set STATE_ZOMBIE */
|
||||
peer->p_psm = (pthread_t)NULL;
|
||||
pthread_detach(pthread_self());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Functions to control the PSM */
|
||||
/************************************************************************/
|
||||
/* Create the PSM thread of one peer structure */
|
||||
int fd_psm_begin(struct fd_peer * peer )
|
||||
{
|
||||
TRACE_ENTRY("%p", peer);
|
||||
|
||||
/* Check the peer and state are OK */
|
||||
CHECK_PARAMS( fd_peer_getstate(peer) == STATE_NEW );
|
||||
|
||||
/* Create the FIFO for events */
|
||||
CHECK_FCT( fd_fifo_new(&peer->p_events, 0) );
|
||||
|
||||
/* Create the PSM controler thread */
|
||||
CHECK_POSIX( pthread_create( &peer->p_psm, NULL, p_psm_th, peer ) );
|
||||
|
||||
/* We're done */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* End the PSM (clean ending) */
|
||||
int fd_psm_terminate(struct fd_peer * peer, char * reason )
|
||||
{
|
||||
TRACE_ENTRY("%p", peer);
|
||||
CHECK_PARAMS( CHECK_PEER(peer) );
|
||||
|
||||
if (fd_peer_getstate(peer) != STATE_ZOMBIE) {
|
||||
CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, reason) );
|
||||
} else {
|
||||
TRACE_DEBUG(FULL, "Peer '%s' was already terminated", peer->p_hdr.info.pi_diamid);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* End the PSM & cleanup the peer structure */
|
||||
void fd_psm_abord(struct fd_peer * peer )
|
||||
{
|
||||
TRACE_ENTRY("%p", peer);
|
||||
|
||||
/* Cancel PSM thread */
|
||||
CHECK_FCT_DO( fd_thr_term(&peer->p_psm), /* continue */ );
|
||||
|
||||
/* Cleanup the data */
|
||||
fd_psm_cleanup(peer, 1);
|
||||
|
||||
/* Destroy the event list */
|
||||
CHECK_FCT_DO( fd_fifo_del(&peer->p_events), /* continue */ );
|
||||
|
||||
/* Remaining cleanups are performed in fd_peer_free */
|
||||
return;
|
||||
}
|
||||
|
||||
350
plat/diameter/libfdcore/p_sr.c
Normal file
350
plat/diameter/libfdcore/p_sr.c
Normal file
@@ -0,0 +1,350 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
/* Structure to store a sent request */
|
||||
struct sentreq {
|
||||
struct fd_list chain; /* the "o" field points directly to the (new) hop-by-hop of the request (uint32_t *) */
|
||||
struct msg *req; /* A request that was sent and not yet answered. */
|
||||
uint32_t prevhbh;/* The value to set back in the hbh header when the message is retrieved */
|
||||
struct fd_list expire; /* the list of expiring requests */
|
||||
struct timespec timeout; /* Cache the expire date of the request so that the timeout thread does not need to get it each time. */
|
||||
struct timespec added_on; /* the time the request was added */
|
||||
};
|
||||
|
||||
/* Find an element in the hbh list, or the following one */
|
||||
static struct fd_list * find_or_next(struct fd_list * srlist, uint32_t hbh, int * match)
|
||||
{
|
||||
struct fd_list * li;
|
||||
*match = 0;
|
||||
for (li = srlist->next; li != srlist; li = li->next) {
|
||||
uint32_t * nexthbh = li->o;
|
||||
if (*nexthbh < hbh)
|
||||
continue;
|
||||
if (*nexthbh == hbh)
|
||||
*match = 1;
|
||||
break;
|
||||
}
|
||||
return li;
|
||||
}
|
||||
|
||||
/* Similar but start from the end, since we add requests in growing hbh order usually */
|
||||
static struct fd_list * find_or_prev(struct fd_list * srlist, uint32_t hbh, int * match)
|
||||
{
|
||||
struct fd_list * li;
|
||||
*match = 0;
|
||||
for (li = srlist->prev; li != srlist; li = li->prev) {
|
||||
uint32_t * prevhbh = li->o;
|
||||
if (*prevhbh > hbh)
|
||||
continue;
|
||||
if (*prevhbh == hbh)
|
||||
*match = 1;
|
||||
break;
|
||||
}
|
||||
return li;
|
||||
}
|
||||
|
||||
static void srl_dump(const char * text, struct fd_list * srlist)
|
||||
{
|
||||
struct fd_list * li;
|
||||
struct timespec now;
|
||||
|
||||
LOG_D("%sSentReq list @%p:", text, srlist);
|
||||
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), );
|
||||
|
||||
for (li = srlist->next; li != srlist; li = li->next) {
|
||||
struct sentreq * sr = (struct sentreq *)li;
|
||||
uint32_t * nexthbh = li->o;
|
||||
|
||||
LOG_D(" - Next req (hbh:0x%x, prev:0x%x): [since %ld.%06ld sec]", *nexthbh, sr->prevhbh,
|
||||
(long)((now.tv_nsec >= sr->added_on.tv_nsec) ? (now.tv_sec - sr->added_on.tv_sec) : (now.tv_sec - sr->added_on.tv_sec - 1)),
|
||||
(long)((now.tv_nsec >= sr->added_on.tv_nsec) ? ((now.tv_nsec - sr->added_on.tv_nsec) / 1000) : ((now.tv_nsec - sr->added_on.tv_nsec + 1000000000) / 1000)));
|
||||
}
|
||||
}
|
||||
|
||||
/* thread that handles messages expiring. The thread is started only when needed */
|
||||
static void * sr_expiry_th(void * arg) {
|
||||
struct sr_list * srlist = arg;
|
||||
|
||||
TRACE_ENTRY("%p", arg);
|
||||
CHECK_PARAMS_DO( arg, return NULL );
|
||||
|
||||
/* Set the thread name */
|
||||
{
|
||||
char buf[48];
|
||||
snprintf(buf, sizeof(buf), "ReqExp/%s", ((struct fd_peer *)(srlist->exp.o))->p_hdr.info.pi_diamid);
|
||||
fd_log_threadname ( buf );
|
||||
}
|
||||
|
||||
do {
|
||||
struct timespec now;
|
||||
struct sentreq * first;
|
||||
struct msg * request;
|
||||
struct fd_peer * sentto;
|
||||
void (*expirecb)(void *, DiamId_t, size_t, struct msg **);
|
||||
void * data;
|
||||
int no_error;
|
||||
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&srlist->mtx), return NULL );
|
||||
pthread_cleanup_push( fd_cleanup_mutex, &srlist->mtx );
|
||||
|
||||
loop:
|
||||
no_error = 0;
|
||||
|
||||
/* Check if there are expiring requests available */
|
||||
if (FD_IS_LIST_EMPTY(&srlist->exp)) {
|
||||
/* Just wait for a change or cancelation */
|
||||
CHECK_POSIX_DO( pthread_cond_wait( &srlist->cnd, &srlist->mtx ), goto unlock );
|
||||
/* Restart the loop on wakeup */
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/* Get the pointer to the request that expires first */
|
||||
first = (struct sentreq *)(srlist->exp.next->o);
|
||||
|
||||
/* Get the current time */
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), goto unlock );
|
||||
|
||||
/* If first request is not expired, we just wait until it happens */
|
||||
if ( TS_IS_INFERIOR( &now, &first->timeout ) ) {
|
||||
|
||||
CHECK_POSIX_DO2( pthread_cond_timedwait( &srlist->cnd, &srlist->mtx, &first->timeout ),
|
||||
ETIMEDOUT, /* ETIMEDOUT is a normal return value, continue */,
|
||||
/* on other error, */ goto unlock );
|
||||
|
||||
/* on wakeup, loop */
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/* Now, the first request in the list is expired; remove it and call the expirecb for it */
|
||||
request = first->req;
|
||||
sentto = first->chain.head->o;
|
||||
|
||||
TRACE_DEBUG(FULL, "Request %x was not answered by %s within the timer delay", *((uint32_t *)first->chain.o), sentto->p_hdr.info.pi_diamid);
|
||||
|
||||
/* Restore the hbhid */
|
||||
*((uint32_t *)first->chain.o) = first->prevhbh;
|
||||
|
||||
/* Free the sentreq information */
|
||||
fd_list_unlink(&first->chain);
|
||||
srlist->cnt--;
|
||||
srlist->cnt_lost++; /* We are not waiting for this answer anymore, but the remote peer may still be processing it. */
|
||||
fd_list_unlink(&first->expire);
|
||||
free(first);
|
||||
|
||||
no_error = 1;
|
||||
unlock:
|
||||
; /* pthread_cleanup_pop sometimes expands as "} ..." and the label before this cause some compilers to complain... */
|
||||
pthread_cleanup_pop( 1 ); /* unlock the mutex */
|
||||
if (!no_error)
|
||||
break;
|
||||
|
||||
|
||||
/* Retrieve callback in the message */
|
||||
CHECK_FCT_DO( fd_msg_anscb_get( request, NULL, &expirecb, &data ), break);
|
||||
ASSERT(expirecb);
|
||||
|
||||
/* Clean up this expirecb from the message */
|
||||
CHECK_FCT_DO( fd_msg_anscb_reset( request, 0, 1 ), break);
|
||||
|
||||
/* Call it */
|
||||
(*expirecb)(data, sentto->p_hdr.info.pi_diamid, sentto->p_hdr.info.pi_diamidlen, &request);
|
||||
|
||||
/* If the callback did not dispose of the message, do it now */
|
||||
if (request) {
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, request, NULL, "Expiration period completed without an answer, and the expiry callback did not dispose of the message.", fd_msg_pmdl_get(request));
|
||||
CHECK_FCT_DO( fd_msg_free(request), /* ignore */ );
|
||||
}
|
||||
|
||||
} while (1);
|
||||
|
||||
ASSERT(0); /* we have encountered a problem, maybe time to signal the framework to terminate? */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Store a new sent request */
|
||||
int fd_p_sr_store(struct sr_list * srlist, struct msg **req, uint32_t *hbhloc, uint32_t hbh_restore)
|
||||
{
|
||||
struct sentreq * sr;
|
||||
struct fd_list * prev;
|
||||
int match;
|
||||
struct timespec * ts;
|
||||
|
||||
TRACE_ENTRY("%p %p %p %x", srlist, req, hbhloc, hbh_restore);
|
||||
CHECK_PARAMS(srlist && req && *req && hbhloc);
|
||||
|
||||
CHECK_MALLOC( sr = malloc(sizeof(struct sentreq)) );
|
||||
memset(sr, 0, sizeof(struct sentreq));
|
||||
fd_list_init(&sr->chain, hbhloc);
|
||||
sr->req = *req;
|
||||
sr->prevhbh = hbh_restore;
|
||||
fd_list_init(&sr->expire, sr);
|
||||
CHECK_SYS( clock_gettime(CLOCK_REALTIME, &sr->added_on) );
|
||||
|
||||
/* Search the place in the list */
|
||||
CHECK_POSIX( pthread_mutex_lock(&srlist->mtx) );
|
||||
prev = find_or_prev(&srlist->srs, *hbhloc, &match);
|
||||
if (match) {
|
||||
TRACE_DEBUG(INFO, "A request with the same hop-by-hop Id (0x%x) was already sent: error", *hbhloc);
|
||||
free(sr);
|
||||
srl_dump("Current list of SR: ", &srlist->srs);
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&srlist->mtx), /* ignore */ );
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Save in the list */
|
||||
*req = NULL;
|
||||
fd_list_insert_after(prev, &sr->chain);
|
||||
srlist->cnt++;
|
||||
|
||||
/* In case of request with a timeout, also store in the timeout list */
|
||||
ts = fd_msg_anscb_gettimeout( sr->req );
|
||||
if (ts) {
|
||||
struct fd_list * li;
|
||||
|
||||
memcpy(&sr->timeout, ts, sizeof(struct timespec));
|
||||
|
||||
/* browse srlist->exp from the end */
|
||||
for (li = srlist->exp.prev; li != &srlist->exp; li = li->prev) {
|
||||
struct sentreq * s = (struct sentreq *)(li->o);
|
||||
if (TS_IS_INFERIOR(&s->timeout, ts))
|
||||
break;
|
||||
}
|
||||
|
||||
fd_list_insert_after(li, &sr->expire);
|
||||
|
||||
/* if the thread does not exist yet, create it */
|
||||
if (srlist->thr == (pthread_t)NULL) {
|
||||
CHECK_POSIX_DO( pthread_create(&srlist->thr, NULL, sr_expiry_th, srlist), /* continue anyway */);
|
||||
} else {
|
||||
/* or, if added in first position, signal the condvar to update the sleep time of the thread */
|
||||
if (li == &srlist->exp) {
|
||||
CHECK_POSIX_DO( pthread_cond_signal(&srlist->cnd), /* continue anyway */);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_POSIX( pthread_mutex_unlock(&srlist->mtx) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fetch a request by hbh */
|
||||
int fd_p_sr_fetch(struct sr_list * srlist, uint32_t hbh, struct msg **req)
|
||||
{
|
||||
struct sentreq * sr;
|
||||
int match;
|
||||
|
||||
TRACE_ENTRY("%p %x %p", srlist, hbh, req);
|
||||
CHECK_PARAMS(srlist && req);
|
||||
|
||||
/* Search the request in the list */
|
||||
CHECK_POSIX( pthread_mutex_lock(&srlist->mtx) );
|
||||
sr = (struct sentreq *)find_or_next(&srlist->srs, hbh, &match);
|
||||
if (!match) {
|
||||
TRACE_DEBUG(INFO, "There is no saved request with this hop-by-hop id (%x)", hbh);
|
||||
srl_dump("Current list of SR: ", &srlist->srs);
|
||||
*req = NULL;
|
||||
if (srlist->cnt_lost > 0) {
|
||||
srlist->cnt_lost--; /* This is probably an answer for a request we already timedout. */
|
||||
} /* else, probably a bug in the remote peer */
|
||||
} else {
|
||||
/* Restore hop-by-hop id */
|
||||
*((uint32_t *)sr->chain.o) = sr->prevhbh;
|
||||
/* Unlink */
|
||||
fd_list_unlink(&sr->chain);
|
||||
srlist->cnt--;
|
||||
fd_list_unlink(&sr->expire);
|
||||
*req = sr->req;
|
||||
free(sr);
|
||||
}
|
||||
CHECK_POSIX( pthread_mutex_unlock(&srlist->mtx) );
|
||||
|
||||
/* do not stop the expire thread here, it might cause creating/destroying it very often otherwise */
|
||||
|
||||
/* Done */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Failover requests (free or requeue routables) */
|
||||
void fd_p_sr_failover(struct sr_list * srlist)
|
||||
{
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&srlist->mtx), /* continue anyway */ );
|
||||
while (!FD_IS_LIST_EMPTY(&srlist->srs)) {
|
||||
struct sentreq * sr = (struct sentreq *)(srlist->srs.next);
|
||||
fd_list_unlink(&sr->chain);
|
||||
srlist->cnt--;
|
||||
fd_list_unlink(&sr->expire);
|
||||
if (fd_msg_is_routable(sr->req)) {
|
||||
struct msg_hdr * hdr = NULL;
|
||||
int ret;
|
||||
|
||||
/* Set the 'T' flag */
|
||||
CHECK_FCT_DO(fd_msg_hdr(sr->req, &hdr), /* continue */);
|
||||
if (hdr)
|
||||
hdr->msg_flags |= CMD_FLAG_RETRANSMIT;
|
||||
|
||||
/* Restore the original hop-by-hop id of the request */
|
||||
*((uint32_t *)sr->chain.o) = sr->prevhbh;
|
||||
|
||||
fd_hook_call(HOOK_MESSAGE_FAILOVER, sr->req, (struct fd_peer *)srlist->srs.o, NULL, fd_msg_pmdl_get(sr->req));
|
||||
|
||||
/* Requeue for sending to another peer */
|
||||
CHECK_FCT_DO( ret = fd_fifo_post_noblock(fd_g_outgoing, (void *)&sr->req),
|
||||
{
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "Internal error: error while requeuing during failover: %s", strerror(ret));
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, sr->req, NULL, buf, fd_msg_pmdl_get(sr->req));
|
||||
CHECK_FCT_DO(fd_msg_free(sr->req), /* What can we do more? */)
|
||||
});
|
||||
} else {
|
||||
/* Just free the request. */
|
||||
/* fd_hook_call(HOOK_MESSAGE_DROPPED, sr->req, NULL, "Sent & unanswered local message discarded during failover.", fd_msg_pmdl_get(sr->req)); */
|
||||
CHECK_FCT_DO(fd_msg_free(sr->req), /* Ignore */);
|
||||
}
|
||||
free(sr);
|
||||
}
|
||||
/* The list of expiring requests must be empty now */
|
||||
ASSERT( FD_IS_LIST_EMPTY(&srlist->exp) );
|
||||
ASSERT( srlist->cnt == 0 ); /* debug the counter management if needed */
|
||||
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&srlist->mtx), /* continue anyway */ );
|
||||
|
||||
/* Terminate the expiry thread (must be done when the lock can be taken) */
|
||||
CHECK_FCT_DO( fd_thr_term(&srlist->thr), /* ignore error */ );
|
||||
}
|
||||
|
||||
700
plat/diameter/libfdcore/peers.c
Normal file
700
plat/diameter/libfdcore/peers.c
Normal file
@@ -0,0 +1,700 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
/* Global list of peers */
|
||||
struct fd_list fd_g_peers = FD_LIST_INITIALIZER(fd_g_peers);
|
||||
pthread_rwlock_t fd_g_peers_rw = PTHREAD_RWLOCK_INITIALIZER;
|
||||
|
||||
/* List of active peers */
|
||||
struct fd_list fd_g_activ_peers = FD_LIST_INITIALIZER(fd_g_activ_peers); /* peers linked by their p_actives oredered by p_diamid */
|
||||
pthread_rwlock_t fd_g_activ_peers_rw = PTHREAD_RWLOCK_INITIALIZER;
|
||||
|
||||
/* List of validation callbacks (registered with fd_peer_validate_register) */
|
||||
static struct fd_list validators = FD_LIST_INITIALIZER(validators); /* list items are simple fd_list with "o" pointing to the callback */
|
||||
static pthread_rwlock_t validators_rw = PTHREAD_RWLOCK_INITIALIZER;
|
||||
|
||||
|
||||
/* Alloc / reinit a peer structure. if *ptr is not NULL, it must already point to a valid struct fd_peer. */
|
||||
int fd_peer_alloc(struct fd_peer ** ptr)
|
||||
{
|
||||
struct fd_peer *p;
|
||||
|
||||
TRACE_ENTRY("%p", ptr);
|
||||
CHECK_PARAMS(ptr);
|
||||
|
||||
if (*ptr) {
|
||||
p = *ptr;
|
||||
} else {
|
||||
CHECK_MALLOC( p = malloc(sizeof(struct fd_peer)) );
|
||||
*ptr = p;
|
||||
}
|
||||
|
||||
/* Now initialize the content */
|
||||
memset(p, 0, sizeof(struct fd_peer));
|
||||
|
||||
fd_list_init(&p->p_hdr.chain, p);
|
||||
|
||||
fd_list_init(&p->p_hdr.info.pi_endpoints, p);
|
||||
fd_list_init(&p->p_hdr.info.runtime.pir_apps, p);
|
||||
|
||||
p->p_eyec = EYEC_PEER;
|
||||
CHECK_POSIX( pthread_mutex_init(&p->p_state_mtx, NULL) );
|
||||
|
||||
fd_list_init(&p->p_actives, p);
|
||||
fd_list_init(&p->p_expiry, p);
|
||||
CHECK_FCT( fd_fifo_new(&p->p_tosend, 1024) );// initial is 5
|
||||
CHECK_FCT( fd_fifo_new(&p->p_tofailover, 0) );
|
||||
p->p_hbh = lrand48();
|
||||
|
||||
fd_list_init(&p->p_sr.srs, p);
|
||||
fd_list_init(&p->p_sr.exp, p);
|
||||
CHECK_POSIX( pthread_mutex_init(&p->p_sr.mtx, NULL) );
|
||||
CHECK_POSIX( pthread_cond_init(&p->p_sr.cnd, NULL) );
|
||||
|
||||
fd_list_init(&p->p_connparams, p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add a new peer entry */
|
||||
int fd_peer_add ( struct peer_info * info, const char * orig_dbg, void (*cb)(struct peer_info *, void *), void * cb_data )
|
||||
{
|
||||
struct fd_peer *p = NULL;
|
||||
struct fd_list * li, *li_inf;
|
||||
int ret = 0;
|
||||
|
||||
TRACE_ENTRY("%p %p %p %p", info, orig_dbg, cb, cb_data);
|
||||
CHECK_PARAMS(info && info->pi_diamid);
|
||||
|
||||
if (info->config.pic_realm) {
|
||||
if (!fd_os_is_valid_DiameterIdentity((os0_t)info->config.pic_realm, strlen(info->config.pic_realm))) {
|
||||
TRACE_DEBUG(INFO, "'%s' is not a valid DiameterIdentity.", info->config.pic_realm);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a structure to contain the new peer information */
|
||||
CHECK_FCT( fd_peer_alloc(&p) );
|
||||
|
||||
/* Copy the informations from the parameters received */
|
||||
p->p_hdr.info.pi_diamid = info->pi_diamid;
|
||||
CHECK_FCT( fd_os_validate_DiameterIdentity(&p->p_hdr.info.pi_diamid, &p->p_hdr.info.pi_diamidlen, 1) );
|
||||
|
||||
memcpy( &p->p_hdr.info.config, &info->config, sizeof(p->p_hdr.info.config) );
|
||||
|
||||
/* Duplicate the strings if provided */
|
||||
if (info->config.pic_realm) {
|
||||
CHECK_MALLOC( p->p_hdr.info.config.pic_realm = strdup(info->config.pic_realm) );
|
||||
}
|
||||
if (info->config.pic_priority) {
|
||||
CHECK_MALLOC( p->p_hdr.info.config.pic_priority = strdup(info->config.pic_priority) );
|
||||
}
|
||||
|
||||
/* Move the list of endpoints into the peer */
|
||||
if (info->pi_endpoints.next)
|
||||
while (!FD_IS_LIST_EMPTY( &info->pi_endpoints ) ) {
|
||||
li = info->pi_endpoints.next;
|
||||
fd_list_unlink(li);
|
||||
fd_list_insert_before(&p->p_hdr.info.pi_endpoints, li);
|
||||
}
|
||||
|
||||
/* The internal data */
|
||||
if (orig_dbg) {
|
||||
CHECK_MALLOC( p->p_dbgorig = strdup(orig_dbg) );
|
||||
} else {
|
||||
CHECK_MALLOC( p->p_dbgorig = strdup("unspecified") );
|
||||
}
|
||||
p->p_cb = cb;
|
||||
p->p_cb_data = cb_data;
|
||||
|
||||
/* Ok, now check if we don't already have an entry with the same Diameter Id, and insert this one */
|
||||
CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_peers_rw) );
|
||||
li_inf = &fd_g_peers;
|
||||
for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
|
||||
struct fd_peer * next = (struct fd_peer *)li;
|
||||
int cont;
|
||||
int cmp = fd_os_almostcasesrch( p->p_hdr.info.pi_diamid, p->p_hdr.info.pi_diamidlen,
|
||||
next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen,
|
||||
&cont );
|
||||
if (cmp > 0)
|
||||
li_inf = li; /* it will come after this element, for sure */
|
||||
|
||||
if (cmp == 0) {
|
||||
ret = EEXIST; /* we have a duplicate */
|
||||
break;
|
||||
}
|
||||
if (!cont)
|
||||
break;
|
||||
}
|
||||
|
||||
/* We can insert the new peer object */
|
||||
if (! ret)
|
||||
do {
|
||||
/* Update expiry list */
|
||||
CHECK_FCT_DO( ret = fd_p_expi_update( p ), break );
|
||||
|
||||
/* Insert the new element in the list */
|
||||
fd_list_insert_after( li_inf, &p->p_hdr.chain );
|
||||
} while (0);
|
||||
|
||||
CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
|
||||
if (ret) {
|
||||
CHECK_FCT( fd_peer_free(&p) );
|
||||
} else {
|
||||
CHECK_FCT( fd_psm_begin(p) );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Search for a peer */
|
||||
int fd_peer_getbyid( DiamId_t diamid, size_t diamidlen, int igncase, struct peer_hdr ** peer )
|
||||
{
|
||||
struct fd_list * li;
|
||||
TRACE_ENTRY("%p %zd %d %p", diamid, diamidlen, igncase, peer);
|
||||
CHECK_PARAMS( diamid && diamidlen && peer );
|
||||
|
||||
*peer = NULL;
|
||||
|
||||
/* Search in the list */
|
||||
CHECK_POSIX( pthread_rwlock_rdlock(&fd_g_peers_rw) );
|
||||
if (igncase) {
|
||||
for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
|
||||
struct fd_peer * next = (struct fd_peer *)li;
|
||||
int cmp, cont;
|
||||
cmp = fd_os_almostcasesrch( diamid, diamidlen, next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen, &cont );
|
||||
if (cmp == 0) {
|
||||
*peer = &next->p_hdr;
|
||||
break;
|
||||
}
|
||||
if (!cont)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LOG_D("fd_peer_getbyid enter");
|
||||
for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
|
||||
struct fd_peer * next = (struct fd_peer *)li;
|
||||
LOG_D("fd_peer_getbyid src[%u,%s] peer[%u,%s]",
|
||||
(unsigned int)diamidlen,
|
||||
diamid,
|
||||
(unsigned int)( next->p_hdr.info.pi_diamidlen ),
|
||||
next->p_hdr.info.pi_diamid);
|
||||
int cmp = fd_os_cmp( diamid, diamidlen, next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen );
|
||||
if (cmp > 0)
|
||||
continue;
|
||||
if (cmp == 0)
|
||||
*peer = &next->p_hdr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define free_null( _v ) \
|
||||
if (_v) { \
|
||||
free(_v); \
|
||||
(_v) = NULL; \
|
||||
}
|
||||
|
||||
#define free_list( _l ) \
|
||||
while (!FD_IS_LIST_EMPTY(_l)) { \
|
||||
struct fd_list * __li = ((struct fd_list *)(_l))->next; \
|
||||
fd_list_unlink(__li); \
|
||||
free(__li); \
|
||||
}
|
||||
|
||||
/* Empty the lists of p_tosend, p_failover, and p_sentreq messages */
|
||||
void fd_peer_failover_msg(struct fd_peer * peer)
|
||||
{
|
||||
struct msg *m;
|
||||
TRACE_ENTRY("%p", peer);
|
||||
CHECK_PARAMS_DO(CHECK_PEER(peer), return);
|
||||
|
||||
/* Requeue all messages in the "out" queue */
|
||||
while ( fd_fifo_tryget(peer->p_tosend, &m) == 0 ) {
|
||||
/* but only if they are routable */
|
||||
if (fd_msg_is_routable(m)) {
|
||||
fd_hook_call(HOOK_MESSAGE_FAILOVER, m, peer, NULL, fd_msg_pmdl_get(m));
|
||||
CHECK_FCT_DO(fd_fifo_post_noblock(fd_g_outgoing, (void *)&m),
|
||||
{
|
||||
/* fallback: destroy the message */
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, m, NULL, "Internal error: unable to requeue this message during failover process", fd_msg_pmdl_get(m));
|
||||
CHECK_FCT_DO(fd_msg_free(m), /* What can we do more? */)
|
||||
} );
|
||||
} else {
|
||||
/* Just free it */
|
||||
/* fd_hook_call(HOOK_MESSAGE_DROPPED, m, NULL, "Non-routable message freed during handover", fd_msg_pmdl_get(m)); */
|
||||
CHECK_FCT_DO(fd_msg_free(m), /* What can we do more? */)
|
||||
}
|
||||
}
|
||||
|
||||
/* Requeue all messages in the "failover" queue */
|
||||
while ( fd_fifo_tryget(peer->p_tofailover, &m) == 0 ) {
|
||||
fd_hook_call(HOOK_MESSAGE_FAILOVER, m, peer, NULL, fd_msg_pmdl_get(m));
|
||||
CHECK_FCT_DO(fd_fifo_post_noblock(fd_g_outgoing, (void *)&m),
|
||||
{
|
||||
/* fallback: destroy the message */
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, m, NULL, "Internal error: unable to requeue this message during failover process", fd_msg_pmdl_get(m));
|
||||
CHECK_FCT_DO(fd_msg_free(m), /* What can we do more? */)
|
||||
} );
|
||||
}
|
||||
|
||||
/* Requeue all routable sent requests */
|
||||
fd_p_sr_failover(&peer->p_sr);
|
||||
|
||||
/* Done */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Describe the current connection */
|
||||
int fd_peer_cnx_proto_info(struct peer_hdr *peer, char * buf, size_t len)
|
||||
{
|
||||
struct fd_peer * p = (struct fd_peer *)peer;
|
||||
TRACE_ENTRY("%p %p %zd", peer, buf, len);
|
||||
CHECK_PARAMS(CHECK_PEER(peer) && buf && len);
|
||||
|
||||
if (p->p_cnxctx) {
|
||||
CHECK_FCT(fd_cnx_proto_info(p->p_cnxctx, buf, len));
|
||||
} else if (p->p_receiver) {
|
||||
CHECK_FCT(fd_cnx_proto_info(p->p_receiver, buf, len));
|
||||
} else {
|
||||
snprintf(buf, len, "Not Connected");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the value of srlist->cnt */
|
||||
int fd_peer_get_load_pending(struct peer_hdr *peer, long * to_receive, long * to_send)
|
||||
{
|
||||
struct fd_peer * p = (struct fd_peer *)peer;
|
||||
TRACE_ENTRY("%p %p %p", peer, to_receive, to_send);
|
||||
CHECK_PARAMS(CHECK_PEER(peer));
|
||||
|
||||
if (to_receive) {
|
||||
CHECK_POSIX( pthread_mutex_lock(&p->p_sr.mtx) );
|
||||
*to_receive = p->p_sr.cnt;
|
||||
CHECK_POSIX( pthread_mutex_unlock(&p->p_sr.mtx) );
|
||||
}
|
||||
if (to_send) {
|
||||
CHECK_POSIX( pthread_mutex_lock(&p->p_state_mtx) );
|
||||
*to_send = p->p_reqin_count;
|
||||
CHECK_POSIX( pthread_mutex_unlock(&p->p_state_mtx) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Destroy a structure once cleanups have been performed (fd_psm_abord, ...) */
|
||||
int fd_peer_free(struct fd_peer ** ptr)
|
||||
{
|
||||
struct fd_peer *p;
|
||||
|
||||
TRACE_ENTRY("%p", ptr);
|
||||
CHECK_PARAMS(ptr);
|
||||
p = *ptr;
|
||||
*ptr = NULL;
|
||||
CHECK_PARAMS(p);
|
||||
|
||||
CHECK_PARAMS( FD_IS_LIST_EMPTY(&p->p_hdr.chain) );
|
||||
|
||||
free_null(p->p_hdr.info.pi_diamid);
|
||||
|
||||
free_null(p->p_hdr.info.config.pic_realm);
|
||||
free_null(p->p_hdr.info.config.pic_priority);
|
||||
|
||||
free_null(p->p_hdr.info.runtime.pir_realm);
|
||||
free_null(p->p_hdr.info.runtime.pir_prodname);
|
||||
free_list( &p->p_hdr.info.runtime.pir_apps );
|
||||
|
||||
free_list( &p->p_hdr.info.pi_endpoints );
|
||||
|
||||
free_null(p->p_dbgorig);
|
||||
|
||||
fd_list_unlink(&p->p_expiry);
|
||||
fd_list_unlink(&p->p_actives);
|
||||
|
||||
CHECK_FCT_DO( fd_fifo_del(&p->p_tosend), /* continue */ );
|
||||
CHECK_FCT_DO( fd_fifo_del(&p->p_tofailover), /* continue */ );
|
||||
CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_state_mtx), /* continue */);
|
||||
CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_sr.mtx), /* continue */);
|
||||
CHECK_POSIX_DO( pthread_cond_destroy(&p->p_sr.cnd), /* continue */);
|
||||
|
||||
/* If the callback is still around... */
|
||||
if (p->p_cb)
|
||||
(*p->p_cb)(NULL, p->p_cb_data);
|
||||
|
||||
/* Free the structure */
|
||||
free(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Terminate peer module (destroy all peers, first gently, then violently) */
|
||||
int fd_peer_fini()
|
||||
{
|
||||
struct fd_list * li;
|
||||
struct fd_list purge = FD_LIST_INITIALIZER(purge); /* Store zombie peers here */
|
||||
int list_empty;
|
||||
struct timespec wait_until, now;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
CHECK_FCT_DO(fd_p_expi_fini(), /* continue */);
|
||||
|
||||
TRACE_DEBUG(INFO, "Sending terminate signal to all peer connections");
|
||||
|
||||
CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
|
||||
for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
|
||||
struct fd_peer * peer = (struct fd_peer *)li->o;
|
||||
|
||||
if (fd_peer_getstate(peer) != STATE_ZOMBIE) {
|
||||
CHECK_FCT_DO( fd_psm_terminate(peer, "REBOOTING"), /* continue */ );
|
||||
} else {
|
||||
li = li->prev; /* to avoid breaking the loop */
|
||||
fd_list_unlink(&peer->p_hdr.chain);
|
||||
fd_list_insert_before(&purge, &peer->p_hdr.chain);
|
||||
}
|
||||
}
|
||||
list_empty = FD_IS_LIST_EMPTY(&fd_g_peers);
|
||||
CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
|
||||
|
||||
if (!list_empty) {
|
||||
CHECK_SYS( clock_gettime(CLOCK_REALTIME, &now) );
|
||||
fd_psm_start(); /* just in case */
|
||||
TRACE_DEBUG(INFO, "Waiting for connections shutdown... (%d sec max)", DPR_TIMEOUT + 1);
|
||||
wait_until.tv_sec = now.tv_sec + DPR_TIMEOUT + 1;
|
||||
wait_until.tv_nsec = now.tv_nsec;
|
||||
}
|
||||
|
||||
while ((!list_empty) && (TS_IS_INFERIOR(&now, &wait_until))) {
|
||||
|
||||
/* Allow the PSM(s) to execute */
|
||||
usleep(100000);
|
||||
|
||||
/* Remove zombie peers */
|
||||
CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
|
||||
for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
|
||||
struct fd_peer * peer = (struct fd_peer *)li->o;
|
||||
if (fd_peer_getstate(peer) == STATE_ZOMBIE) {
|
||||
li = li->prev; /* to avoid breaking the loop */
|
||||
fd_list_unlink(&peer->p_hdr.chain);
|
||||
fd_list_insert_before(&purge, &peer->p_hdr.chain);
|
||||
}
|
||||
}
|
||||
list_empty = FD_IS_LIST_EMPTY(&fd_g_peers);
|
||||
CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
|
||||
CHECK_SYS( clock_gettime(CLOCK_REALTIME, &now) );
|
||||
}
|
||||
|
||||
if (!list_empty) {
|
||||
TRACE_DEBUG(INFO, "Forcing connections shutdown");
|
||||
CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
|
||||
while (!FD_IS_LIST_EMPTY(&fd_g_peers)) {
|
||||
struct fd_peer * peer = (struct fd_peer *)(fd_g_peers.next->o);
|
||||
fd_psm_abord(peer);
|
||||
fd_list_unlink(&peer->p_hdr.chain);
|
||||
fd_list_insert_before(&purge, &peer->p_hdr.chain);
|
||||
}
|
||||
CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
|
||||
}
|
||||
|
||||
/* Free memory objects of all peers */
|
||||
while (!FD_IS_LIST_EMPTY(&purge)) {
|
||||
struct fd_peer * peer = (struct fd_peer *)(purge.next->o);
|
||||
fd_list_unlink(&peer->p_hdr.chain);
|
||||
fd_peer_free(&peer);
|
||||
}
|
||||
|
||||
/* Now empty the validators list */
|
||||
CHECK_FCT_DO( pthread_rwlock_wrlock(&validators_rw), /* continue */ );
|
||||
while (!FD_IS_LIST_EMPTY( &validators )) {
|
||||
struct fd_list * v = validators.next;
|
||||
fd_list_unlink(v);
|
||||
free(v);
|
||||
}
|
||||
CHECK_FCT_DO( pthread_rwlock_unlock(&validators_rw), /* continue */ );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Dump info of one peer */
|
||||
DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump, struct peer_hdr * p, int details)
|
||||
{
|
||||
FD_DUMP_HANDLE_OFFSET();
|
||||
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{peer}(@%p): ", p), return NULL);
|
||||
|
||||
if (!CHECK_PEER(p)) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
|
||||
} else {
|
||||
struct fd_peer * peer = (struct fd_peer *)p;
|
||||
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s [%s, cnt:%ldsr,%ldpa]", peer->p_hdr.info.pi_diamid, STATE_STR(fd_peer_getstate(peer)), peer->p_sr.cnt, peer->p_reqin_count), return NULL);
|
||||
if (details > 0) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " rlm:%s", peer->p_hdr.info.runtime.pir_realm ?: "<unknown>"), return NULL);
|
||||
if (peer->p_hdr.info.runtime.pir_prodname) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " ['%s' %u]", peer->p_hdr.info.runtime.pir_prodname, peer->p_hdr.info.runtime.pir_firmrev), return NULL);
|
||||
}
|
||||
}
|
||||
if (details > 1) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " [from:%s] flags:%s%s%s%s%s%s%s%s lft:%ds",
|
||||
peer->p_dbgorig ?: "unset",
|
||||
peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_DEFAULT ? "-" :
|
||||
(peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP ? "4" : "6"),
|
||||
peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_DEFAULT ? "-" :
|
||||
(peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_TCP ? "T" : "S"),
|
||||
peer->p_hdr.info.config.pic_flags.alg ? "P" : "-",
|
||||
peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE ? "N" :"-",
|
||||
peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD ? "O" :"-",
|
||||
peer->p_hdr.info.config.pic_flags.sctpsec & PI_SCTPSEC_3436 ? "3" :"-",
|
||||
peer->p_hdr.info.config.pic_flags.exp ? "E" : "-",
|
||||
peer->p_hdr.info.config.pic_flags.persist ? "P" : "-",
|
||||
peer->p_hdr.info.config.pic_lft), return NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return *buf;
|
||||
}
|
||||
|
||||
/* Dump the list of peers */
|
||||
DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump_list, int details)
|
||||
{
|
||||
struct fd_list * li;
|
||||
FD_DUMP_HANDLE_OFFSET();
|
||||
|
||||
CHECK_FCT_DO( pthread_rwlock_rdlock(&fd_g_peers_rw), /* continue */ );
|
||||
|
||||
for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
|
||||
CHECK_MALLOC_DO( fd_peer_dump(FD_DUMP_STD_PARAMS, (struct peer_hdr *)li->o, details), break);
|
||||
if (li->next != &fd_g_peers) {
|
||||
CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), break);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
|
||||
return *buf;
|
||||
}
|
||||
|
||||
static struct dict_object *avp_oh_model = NULL;
|
||||
static pthread_mutex_t cache_avp_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* Handle an incoming CER request on a new connection */
|
||||
int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx )
|
||||
{
|
||||
struct msg * msg;
|
||||
struct avp *avp_oh;
|
||||
struct avp_hdr * avp_hdr;
|
||||
struct fd_list * li, *li_inf;
|
||||
int found = 0;
|
||||
int ret = 0;
|
||||
struct fd_peer * peer;
|
||||
struct cnx_incoming * ev_data;
|
||||
|
||||
TRACE_ENTRY("%p %p", cer, cnx);
|
||||
CHECK_PARAMS(cer && *cer && cnx && *cnx);
|
||||
|
||||
msg = *cer;
|
||||
|
||||
/* If needed, resolve the dictionary model for Origin-Host */
|
||||
CHECK_POSIX( pthread_mutex_lock(&cache_avp_lock) );
|
||||
if (!avp_oh_model) {
|
||||
avp_code_t code = AC_ORIGIN_HOST;
|
||||
CHECK_FCT_DO( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE, &code, &avp_oh_model, ENOENT),
|
||||
{ LOG_E("Cannot find Origin-Host AVP definition in the dictionary!"); (void) pthread_mutex_unlock(&cache_avp_lock); return __ret__; } );
|
||||
}
|
||||
CHECK_POSIX( pthread_mutex_unlock(&cache_avp_lock) );
|
||||
|
||||
/* Find the Diameter Identity of the remote peer in the message */
|
||||
CHECK_FCT( fd_msg_search_avp ( msg, avp_oh_model, &avp_oh ) );
|
||||
ASSERT(avp_oh); /* otherwise it should not have passed rules validation, right? */
|
||||
CHECK_FCT( fd_msg_avp_hdr ( avp_oh, &avp_hdr ) );
|
||||
|
||||
/* First, check if the Origin-Host value is valid */
|
||||
if (!fd_os_is_valid_DiameterIdentity(avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len)) {
|
||||
CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, cer, MSGFL_ANSW_ERROR ) );
|
||||
CHECK_FCT( fd_msg_rescode_set(*cer, "DIAMETER_INVALID_AVP_VALUE",
|
||||
"Your Origin-Host contains invalid characters.", avp_oh, 1 ) );
|
||||
|
||||
fd_hook_call(HOOK_PEER_CONNECT_FAILED, *cer, NULL, "Received CER with invalid Origin-Host AVP", NULL);
|
||||
|
||||
CHECK_FCT( fd_out_send(cer, *cnx, NULL, 0) );
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Search if we already have this peer id in our list. We take directly the write lock so that we don't need to upgrade if it is a new peer.
|
||||
* There is space for a small optimization here if needed.
|
||||
*/
|
||||
CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_peers_rw) );
|
||||
|
||||
li_inf = &fd_g_peers;
|
||||
for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
|
||||
int cmp, cont;
|
||||
peer = (struct fd_peer *)li;
|
||||
cmp = fd_os_almostcasesrch( avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len, peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen, &cont );
|
||||
if (cmp > 0) {
|
||||
li_inf = li;
|
||||
}
|
||||
if (cmp == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
if (!cont)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
/* Create a new peer entry for this new remote peer */
|
||||
peer = NULL;
|
||||
CHECK_FCT_DO( ret = fd_peer_alloc(&peer), goto out );
|
||||
|
||||
/* Set the peer Diameter Id and the responder flag parameters */
|
||||
CHECK_MALLOC_DO( peer->p_hdr.info.pi_diamid = os0dup(avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len),
|
||||
{ ret = ENOMEM; goto out; } );
|
||||
peer->p_hdr.info.pi_diamidlen = avp_hdr->avp_value->os.len;
|
||||
CHECK_MALLOC_DO( peer->p_dbgorig = strdup(fd_cnx_getid(*cnx)), { ret = ENOMEM; goto out; } );
|
||||
peer->p_flags.pf_responder = 1;
|
||||
peer->p_flags.pf_delete = 1;
|
||||
|
||||
LOG_D("Created new peer object for incoming CER: %s", peer->p_hdr.info.pi_diamid);
|
||||
|
||||
#ifndef DISABLE_PEER_EXPIRY
|
||||
/* Set this peer to expire on inactivity */
|
||||
peer->p_hdr.info.config.pic_flags.exp = PI_EXP_INACTIVE;
|
||||
peer->p_hdr.info.config.pic_lft = 3600; /* 1 hour without any message
|
||||
-- RFC3539 states that this must not be inferior to BRINGDOWN_INTERVAL = 5 minutes */
|
||||
|
||||
CHECK_FCT_DO( ret = fd_p_expi_update( peer ), goto out );
|
||||
#endif /* DISABLE_PEER_EXPIRY */
|
||||
|
||||
/* Insert the new peer in the list (the PSM will take care of setting the expiry after validation) */
|
||||
fd_list_insert_after( li_inf, &peer->p_hdr.chain );
|
||||
|
||||
/* Start the PSM, which will receive the event below */
|
||||
CHECK_FCT_DO( ret = fd_psm_begin(peer), goto out );
|
||||
} else {
|
||||
/* Check if the peer is in zombie state */
|
||||
if (fd_peer_getstate(peer) == STATE_ZOMBIE) {
|
||||
/* Re-activate the peer */
|
||||
if (peer->p_hdr.info.config.pic_flags.exp)
|
||||
peer->p_flags.pf_responder = 1;
|
||||
CHECK_POSIX_DO( pthread_mutex_lock(&peer->p_state_mtx), );
|
||||
peer->p_state = STATE_NEW;
|
||||
CHECK_POSIX_DO( pthread_mutex_unlock(&peer->p_state_mtx), );
|
||||
peer->p_flags.pf_localterm = 0;
|
||||
CHECK_FCT_DO( ret = fd_psm_begin(peer), goto out );
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the new connection event to the PSM */
|
||||
CHECK_MALLOC_DO( ev_data = malloc(sizeof(struct cnx_incoming)), { ret = ENOMEM; goto out; } );
|
||||
memset(ev_data, 0, sizeof(*ev_data));
|
||||
|
||||
ev_data->cer = msg;
|
||||
ev_data->cnx = *cnx;
|
||||
ev_data->validate = !found;
|
||||
|
||||
CHECK_FCT_DO( ret = fd_event_send(peer->p_events, FDEVP_CNX_INCOMING, sizeof(*ev_data), ev_data), goto out );
|
||||
|
||||
out:
|
||||
CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
|
||||
|
||||
if (ret == 0) {
|
||||
/* Reset the "out" parameters, so that they are not cleanup on function return. */
|
||||
*cer = NULL;
|
||||
*cnx = NULL;
|
||||
} else {
|
||||
char buf[1024];
|
||||
snprintf(buf, sizeof(buf), "An error occurred while processing new incoming CER: %s", strerror(ret));
|
||||
fd_hook_call(HOOK_PEER_CONNECT_FAILED, *cer, NULL, buf, NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Save a callback to accept / reject incoming unknown peers */
|
||||
int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */, int (**cb2)(struct peer_info *)) )
|
||||
{
|
||||
struct fd_list * v;
|
||||
|
||||
TRACE_ENTRY("%p", peer_validate);
|
||||
CHECK_PARAMS(peer_validate);
|
||||
|
||||
/* Alloc a new entry */
|
||||
CHECK_MALLOC( v = malloc(sizeof(struct fd_list)) );
|
||||
fd_list_init( v, peer_validate );
|
||||
|
||||
/* Add at the beginning of the list */
|
||||
CHECK_FCT( pthread_rwlock_wrlock(&validators_rw) );
|
||||
fd_list_insert_after(&validators, v);
|
||||
CHECK_FCT( pthread_rwlock_unlock(&validators_rw));
|
||||
|
||||
/* Done! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Validate a peer by calling the callbacks in turn -- return 0 if the peer is validated, ! 0 in case of error (>0) or if the peer is rejected (-1) */
|
||||
int fd_peer_validate( struct fd_peer * peer )
|
||||
{
|
||||
int ret = 0;
|
||||
struct fd_list * v;
|
||||
|
||||
CHECK_FCT( pthread_rwlock_rdlock(&validators_rw) );
|
||||
for (v = validators.next; v != &validators; v = v->next) {
|
||||
int auth = 0;
|
||||
pthread_cleanup_push(fd_cleanup_rwlock, &validators_rw);
|
||||
CHECK_FCT_DO( ret = ((int(*)(struct peer_info *, int *, int (**)(struct peer_info *)))(v->o)) (&peer->p_hdr.info, &auth, &peer->p_cb2), );
|
||||
pthread_cleanup_pop(0);
|
||||
if (ret)
|
||||
goto out;
|
||||
if (auth) {
|
||||
ret = (auth > 0) ? 0 : -1;
|
||||
goto out;
|
||||
}
|
||||
peer->p_cb2 = NULL;
|
||||
}
|
||||
|
||||
/* No callback has given a firm result, the default is to reject */
|
||||
ret = -1;
|
||||
ret = 0;
|
||||
out:
|
||||
CHECK_FCT( pthread_rwlock_unlock(&validators_rw));
|
||||
return ret;
|
||||
}
|
||||
86
plat/diameter/libfdcore/queues.c
Normal file
86
plat/diameter/libfdcore/queues.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
|
||||
/* The global message queues */
|
||||
struct fifo * fd_g_incoming = NULL;
|
||||
struct fifo * fd_g_outgoing = NULL;
|
||||
struct fifo * fd_g_local = NULL;
|
||||
|
||||
/* Initialize the message queues. */
|
||||
#define FD_MSG_QUEUE_SIZE 2048
|
||||
|
||||
int fd_queues_init(void)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
CHECK_FCT( fd_fifo_new ( &fd_g_incoming, FD_MSG_QUEUE_SIZE ) );
|
||||
CHECK_FCT( fd_fifo_new ( &fd_g_outgoing, FD_MSG_QUEUE_SIZE ) );
|
||||
CHECK_FCT( fd_fifo_new ( &fd_g_local, FD_MSG_QUEUE_SIZE ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Destroy a queue after emptying it (and dumping the content) */
|
||||
int fd_queues_fini(struct fifo ** queue)
|
||||
{
|
||||
struct msg * msg;
|
||||
int ret = 0;
|
||||
|
||||
TRACE_ENTRY("%p", queue);
|
||||
|
||||
/* Note : the threads that post into this queue should already been stopped before this !!! */
|
||||
|
||||
CHECK_PARAMS(queue);
|
||||
if (*queue == NULL)
|
||||
return 0; /* the queue was not already initialized */
|
||||
|
||||
/* Empty all contents */
|
||||
while (1) {
|
||||
/* Check if there is a message in the queue */
|
||||
ret = fd_fifo_tryget(*queue, &msg);
|
||||
if (ret == EWOULDBLOCK)
|
||||
break;
|
||||
CHECK_FCT(ret);
|
||||
|
||||
/* We got one! */
|
||||
fd_hook_call(HOOK_MESSAGE_DROPPED, msg, NULL, "Message lost because framework is terminating.", fd_msg_pmdl_get(msg));
|
||||
fd_msg_free(msg);
|
||||
}
|
||||
|
||||
/* Now, delete the empty queue */
|
||||
CHECK_FCT( fd_fifo_del ( queue ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
1337
plat/diameter/libfdcore/routing_dispatch.c
Normal file
1337
plat/diameter/libfdcore/routing_dispatch.c
Normal file
File diff suppressed because it is too large
Load Diff
1355
plat/diameter/libfdcore/sctp.c
Normal file
1355
plat/diameter/libfdcore/sctp.c
Normal file
File diff suppressed because it is too large
Load Diff
793
plat/diameter/libfdcore/sctp3436.c
Normal file
793
plat/diameter/libfdcore/sctp3436.c
Normal file
@@ -0,0 +1,793 @@
|
||||
/*********************************************************************************************************
|
||||
* Software License Agreement (BSD License) *
|
||||
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
|
||||
* *
|
||||
* Copyright (c) 2013, WIDE Project and NICT *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use of this software in source and binary forms, with or without modification, are *
|
||||
* permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* * Redistributions of source code must retain the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer. *
|
||||
* *
|
||||
* * Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the *
|
||||
* following disclaimer in the documentation and/or other *
|
||||
* materials provided with the distribution. *
|
||||
* *
|
||||
* * Neither the name of the WIDE Project or NICT nor the *
|
||||
* names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without *
|
||||
* specific prior written permission of WIDE Project and *
|
||||
* NICT. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
*********************************************************************************************************/
|
||||
|
||||
/* This file contains code for TLS over multi-stream SCTP wrapper implementation (GnuTLS does not support this) */
|
||||
/* See http://aaa.koganei.wide.ad.jp/blogs/index.php/waaad/2008/08/18/tls-over-sctp for history */
|
||||
|
||||
#include "fdcore-internal.h"
|
||||
#include "cnxctx.h"
|
||||
|
||||
#include <netinet/sctp.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
/*
|
||||
|
||||
Architecture of this wrapper:
|
||||
- we have several fifo queues (1 per stream pairs).
|
||||
GnuTLS is configured to use custom push / pull functions:
|
||||
- the pull function retrieves the data from the fifo queue corresponding to a stream #.
|
||||
- the push function sends the data on a certain stream.
|
||||
We also have a demux thread that reads the socket and store received data in the appropriate fifo
|
||||
|
||||
We have one gnutls_session per stream pair, and as many threads that read the gnutls records and save incoming data to the target queue.
|
||||
|
||||
This complexity is required because we cannot read a socket for a given stream only; we can only get the next message and find its stream.
|
||||
*/
|
||||
|
||||
/* Note that this mechanism is replaced by DTLS in RFC6733 */
|
||||
|
||||
/*************************************************************/
|
||||
/* threads */
|
||||
/*************************************************************/
|
||||
|
||||
/* Demux received data and store in the appropriate fifo */
|
||||
static void * demuxer(void * arg)
|
||||
{
|
||||
struct cnxctx * conn = arg;
|
||||
uint8_t * buf;
|
||||
size_t bufsz;
|
||||
int event;
|
||||
uint16_t strid;
|
||||
|
||||
TRACE_ENTRY("%p", arg);
|
||||
CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out);
|
||||
|
||||
/* Set the thread name */
|
||||
{
|
||||
char buf[48];
|
||||
snprintf(buf, sizeof(buf), "Demuxer (%d:%s)", conn->cc_socket, conn->cc_remid);
|
||||
fd_log_threadname ( buf );
|
||||
}
|
||||
|
||||
ASSERT( conn->cc_proto == IPPROTO_SCTP );
|
||||
ASSERT( fd_cnx_target_queue(conn) );
|
||||
ASSERT( conn->cc_sctp3436_data.array );
|
||||
|
||||
do {
|
||||
CHECK_FCT_DO( fd_sctp_recvmeta(conn, &strid, &buf, &bufsz, &event), goto fatal );
|
||||
switch (event) {
|
||||
case FDEVP_CNX_MSG_RECV:
|
||||
/* Demux this message to the appropriate fifo, another thread will pull, gnutls process, and send to target queue */
|
||||
if (strid < conn->cc_sctp_para.pairs) {
|
||||
CHECK_FCT_DO(fd_event_send(conn->cc_sctp3436_data.array[strid].raw_recv, event, bufsz, buf), goto fatal );
|
||||
} else {
|
||||
TRACE_DEBUG(INFO, "Received packet (%zd bytes) on out-of-range stream #%d from %s, discarded.", bufsz, strid, conn->cc_remid);
|
||||
free(buf);
|
||||
}
|
||||
break;
|
||||
|
||||
case FDEVP_CNX_EP_CHANGE:
|
||||
/* Send this event to the target queue */
|
||||
CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), event, bufsz, buf), goto fatal );
|
||||
break;
|
||||
|
||||
case FDEVP_CNX_ERROR:
|
||||
goto out;
|
||||
|
||||
case FDEVP_CNX_SHUTDOWN:
|
||||
/* Just ignore the notification for now, we will get another error later anyway */
|
||||
continue;
|
||||
|
||||
default:
|
||||
goto fatal;
|
||||
}
|
||||
|
||||
} while (conn->cc_loop);
|
||||
|
||||
out:
|
||||
/* Signal termination of the connection to all decipher threads */
|
||||
for (strid = 0; strid < conn->cc_sctp_para.pairs; strid++) {
|
||||
if (conn->cc_sctp3436_data.array[strid].raw_recv) {
|
||||
CHECK_FCT_DO(fd_event_send(conn->cc_sctp3436_data.array[strid].raw_recv, FDEVP_CNX_ERROR, 0, NULL), goto fatal );
|
||||
}
|
||||
}
|
||||
fd_cnx_markerror(conn);
|
||||
TRACE_DEBUG(FULL, "Thread terminated");
|
||||
return NULL;
|
||||
|
||||
fatal:
|
||||
/* An unrecoverable error occurred, stop the daemon */
|
||||
CHECK_FCT_DO(fd_core_shutdown(), );
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Decrypt the data received in this stream pair and store it in the target queue */
|
||||
static void * decipher(void * arg)
|
||||
{
|
||||
struct sctp3436_ctx * ctx = arg;
|
||||
struct cnxctx *cnx;
|
||||
|
||||
TRACE_ENTRY("%p", arg);
|
||||
CHECK_PARAMS_DO(ctx && ctx->raw_recv && ctx->parent, goto error);
|
||||
cnx = ctx->parent;
|
||||
ASSERT( fd_cnx_target_queue(cnx) );
|
||||
|
||||
/* Set the thread name */
|
||||
{
|
||||
char buf[48];
|
||||
snprintf(buf, sizeof(buf), "Decipher (%hu@%d:%s)", ctx->strid, cnx->cc_socket, cnx->cc_remid);
|
||||
fd_log_threadname ( buf );
|
||||
}
|
||||
|
||||
/* The next function loops while there is no error */
|
||||
CHECK_FCT_DO(fd_tls_rcvthr_core(cnx, ctx->strid ? ctx->session : cnx->cc_tls_para.session), /* continue */);
|
||||
error:
|
||||
fd_cnx_markerror(cnx);
|
||||
TRACE_DEBUG(FULL, "Thread terminated");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
/* push / pull */
|
||||
/*************************************************************/
|
||||
|
||||
#ifdef GNUTLS_VERSION_300
|
||||
/* Check if data is available for gnutls on a given context */
|
||||
static int sctp3436_pull_timeout(gnutls_transport_ptr_t tr, unsigned int ms)
|
||||
{
|
||||
struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) tr;
|
||||
struct timespec tsstore, *ts = NULL;
|
||||
int ret;
|
||||
|
||||
TRACE_ENTRY("%p %d", tr, ms);
|
||||
|
||||
if (ctx->partial.buf)
|
||||
return 1; /* data is already available for pull */
|
||||
|
||||
if (ms) {
|
||||
CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &tsstore), return -1 );
|
||||
tsstore.tv_nsec += (long)ms * 1000000;
|
||||
tsstore.tv_sec += tsstore.tv_nsec / 1000000000L;
|
||||
tsstore.tv_nsec %= 1000000000L;
|
||||
ts = &tsstore;
|
||||
}
|
||||
|
||||
ret = fd_fifo_select ( ctx->raw_recv, ts );
|
||||
if (ret < 0) {
|
||||
errno = -ret;
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
|
||||
/* Send data over the connection, called by gnutls */
|
||||
#ifndef GNUTLS_VERSION_212
|
||||
static ssize_t sctp3436_push(gnutls_transport_ptr_t tr, const void * data, size_t len)
|
||||
{
|
||||
struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) tr;
|
||||
struct iovec iov;
|
||||
|
||||
TRACE_ENTRY("%p %p %zd", tr, data, len);
|
||||
CHECK_PARAMS_DO( tr && data, { errno = EINVAL; return -1; } );
|
||||
|
||||
iov.iov_base = (void *)data;
|
||||
iov.iov_len = len;
|
||||
|
||||
return fd_sctp_sendstrv(ctx->parent, ctx->strid, &iov, 1);
|
||||
}
|
||||
#else /* GNUTLS_VERSION_212 */
|
||||
static ssize_t sctp3436_pushv(gnutls_transport_ptr_t tr, const giovec_t * iov, int iovcnt)
|
||||
{
|
||||
struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) tr;
|
||||
|
||||
TRACE_ENTRY("%p %p %d", tr, iov, iovcnt);
|
||||
CHECK_PARAMS_DO( tr && iov, { errno = EINVAL; return -1; } );
|
||||
|
||||
return fd_sctp_sendstrv(ctx->parent, ctx->strid, (const struct iovec *)iov, iovcnt);
|
||||
}
|
||||
#endif /* GNUTLS_VERSION_212 */
|
||||
|
||||
/* Retrieve data received on a stream and already demultiplexed */
|
||||
static ssize_t sctp3436_pull(gnutls_transport_ptr_t tr, void * buf, size_t len)
|
||||
{
|
||||
struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) tr;
|
||||
size_t pulled = 0;
|
||||
int emptied;
|
||||
|
||||
TRACE_ENTRY("%p %p %zd", tr, buf, len);
|
||||
CHECK_PARAMS_DO( tr && buf, { errno = EINVAL; goto error; } );
|
||||
|
||||
/* If we don't have data available now, pull new message from the fifo -- this is blocking (until the queue is destroyed) */
|
||||
if (!ctx->partial.buf) {
|
||||
int ev;
|
||||
CHECK_FCT_DO( errno = fd_event_get(ctx->raw_recv, &ev, &ctx->partial.bufsz, (void *)&ctx->partial.buf), goto error );
|
||||
if (ev == FDEVP_CNX_ERROR) {
|
||||
/* Documentations says to return 0 on connection closed, but it does hang within gnutls_handshake */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pulled = ctx->partial.bufsz - ctx->partial.offset;
|
||||
if (pulled <= len) {
|
||||
emptied = 1;
|
||||
} else {
|
||||
/* limit to the capacity of destination buffer */
|
||||
emptied = 0;
|
||||
pulled = len;
|
||||
}
|
||||
|
||||
/* Store the data in the destination buffer */
|
||||
memcpy(buf, ctx->partial.buf + ctx->partial.offset, pulled);
|
||||
|
||||
/* Free the buffer if we read all its content, and reset the partial structure */
|
||||
if (emptied) {
|
||||
free(ctx->partial.buf);
|
||||
memset(&ctx->partial, 0, sizeof(ctx->partial));
|
||||
} else {
|
||||
ctx->partial.offset += pulled;
|
||||
}
|
||||
|
||||
/* We are done */
|
||||
return pulled;
|
||||
|
||||
error:
|
||||
gnutls_transport_set_errno (ctx->session, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the parameters of a session to use the appropriate fifo and stream information */
|
||||
#ifndef GNUTLS_VERSION_300
|
||||
GCC_DIAG_OFF("-Wdeprecated-declarations")
|
||||
#endif /* !GNUTLS_VERSION_300 */
|
||||
static void set_sess_transport(gnutls_session_t session, struct sctp3436_ctx *ctx)
|
||||
{
|
||||
/* Set the transport pointer passed to push & pull callbacks */
|
||||
GNUTLS_TRACE( gnutls_transport_set_ptr( session, (gnutls_transport_ptr_t) ctx ) );
|
||||
|
||||
/* Reset the low water value, since we don't use sockets */
|
||||
#ifndef GNUTLS_VERSION_300
|
||||
/* starting version 2.12, this call is not needed */
|
||||
//GNUTLS_TRACE( gnutls_transport_set_lowat( session, 0 ) );
|
||||
#else /* GNUTLS_VERSION_300 */
|
||||
/* but in 3.0 we have to provide the pull_timeout callback */
|
||||
GNUTLS_TRACE( gnutls_transport_set_pull_timeout_function( session, sctp3436_pull_timeout ) );
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
|
||||
/* Set the push and pull callbacks */
|
||||
GNUTLS_TRACE( gnutls_transport_set_pull_function(session, sctp3436_pull) );
|
||||
#ifndef GNUTLS_VERSION_212
|
||||
GNUTLS_TRACE( gnutls_transport_set_push_function(session, sctp3436_push) );
|
||||
#else /* GNUTLS_VERSION_212 */
|
||||
GNUTLS_TRACE( gnutls_transport_set_vec_push_function(session, sctp3436_pushv) );
|
||||
#endif /* GNUTLS_VERSION_212 */
|
||||
|
||||
return;
|
||||
}
|
||||
#ifndef GNUTLS_VERSION_300
|
||||
GCC_DIAG_ON("-Wdeprecated-declarations")
|
||||
#endif /* !GNUTLS_VERSION_300 */
|
||||
|
||||
/*************************************************************/
|
||||
/* Session resuming support */
|
||||
/*************************************************************/
|
||||
|
||||
struct sr_store {
|
||||
struct fd_list list; /* list of sr_data, ordered by key.size then key.data */
|
||||
pthread_rwlock_t lock;
|
||||
struct cnxctx *parent;
|
||||
/* Add another list to chain in a global list to implement a garbage collector on sessions -- TODO if needed */
|
||||
};
|
||||
|
||||
/* Saved master session data for resuming sessions */
|
||||
struct sr_data {
|
||||
struct fd_list chain;
|
||||
gnutls_datum_t key;
|
||||
gnutls_datum_t data;
|
||||
};
|
||||
|
||||
/* Initialize the store area for a connection */
|
||||
static int store_init(struct cnxctx * conn)
|
||||
{
|
||||
TRACE_ENTRY("%p", conn);
|
||||
CHECK_PARAMS( conn && !conn->cc_sctp3436_data.sess_store );
|
||||
|
||||
CHECK_MALLOC( conn->cc_sctp3436_data.sess_store = malloc(sizeof(struct sr_store)) );
|
||||
memset(conn->cc_sctp3436_data.sess_store, 0, sizeof(struct sr_store));
|
||||
|
||||
fd_list_init(&conn->cc_sctp3436_data.sess_store->list, NULL);
|
||||
CHECK_POSIX( pthread_rwlock_init(&conn->cc_sctp3436_data.sess_store->lock, NULL) );
|
||||
conn->cc_sctp3436_data.sess_store->parent = conn;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Destroy the store area for a connection, and all its content */
|
||||
static void store_destroy(struct cnxctx * conn)
|
||||
{
|
||||
/* Del all list entries */
|
||||
TRACE_ENTRY("%p", conn);
|
||||
CHECK_PARAMS_DO( conn, return );
|
||||
|
||||
if (!conn->cc_sctp3436_data.sess_store)
|
||||
return;
|
||||
|
||||
CHECK_POSIX_DO( pthread_rwlock_destroy(&conn->cc_sctp3436_data.sess_store->lock), /* continue */ );
|
||||
|
||||
while (!FD_IS_LIST_EMPTY(&conn->cc_sctp3436_data.sess_store->list)) {
|
||||
struct sr_data * sr = (struct sr_data *) conn->cc_sctp3436_data.sess_store->list.next;
|
||||
fd_list_unlink( &sr->chain );
|
||||
free(sr->key.data);
|
||||
free(sr->data.data);
|
||||
free(sr);
|
||||
}
|
||||
|
||||
free(conn->cc_sctp3436_data.sess_store);
|
||||
conn->cc_sctp3436_data.sess_store = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Search the position (or next if not found) of a key in a store */
|
||||
static struct fd_list * find_or_next(struct sr_store * sto, gnutls_datum_t key, int * match)
|
||||
{
|
||||
struct fd_list * ret;
|
||||
*match = 0;
|
||||
|
||||
for (ret = sto->list.next; ret != &sto->list; ret = ret->next) {
|
||||
int cmp = 0;
|
||||
struct sr_data * sr = (struct sr_data *)ret;
|
||||
|
||||
cmp = fd_os_cmp(key.data, key.size, sr->key.data, sr->key.size);
|
||||
if (cmp > 0)
|
||||
continue;
|
||||
|
||||
if (cmp == 0)
|
||||
*match = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Callbacks for the TLS server side of the connection, called during gnutls_handshake */
|
||||
static int sr_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data)
|
||||
{
|
||||
struct sr_store * sto = (struct sr_store *)dbf;
|
||||
struct fd_list * li;
|
||||
struct sr_data * sr;
|
||||
int match = 0;
|
||||
int ret = 0;
|
||||
|
||||
TRACE_DEBUG( GNUTLS_DBG_LEVEL, "GNUTLS Callback: %s", __PRETTY_FUNCTION__ );
|
||||
CHECK_PARAMS_DO( sto && key.data && data.data, return -1 );
|
||||
|
||||
CHECK_POSIX_DO( pthread_rwlock_wrlock(&sto->lock), return -1 );
|
||||
TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Session store [key ", key.data, key.size, "]");
|
||||
|
||||
li = find_or_next(sto, key, &match);
|
||||
if (match) {
|
||||
sr = (struct sr_data *)li;
|
||||
|
||||
/* Check the data is the same */
|
||||
if ((data.size != sr->data.size) || memcmp(data.data, sr->data.data, data.size)) {
|
||||
TRACE_DEBUG(INFO, "GnuTLS tried to store a session with same key and different data!");
|
||||
TRACE_BUFFER(FD_LOG_DEBUG, INFO, "Session store [key ", key.data, key.size, "]");
|
||||
TRACE_BUFFER(FD_LOG_DEBUG, INFO, " -- old data [", sr->data.data, sr->data.size, "]");
|
||||
TRACE_BUFFER(FD_LOG_DEBUG, INFO, " -- new data [", data.data, data.size, "]");
|
||||
|
||||
ret = -1;
|
||||
} else {
|
||||
TRACE_DEBUG(GNUTLS_DBG_LEVEL, "GnuTLS tried to store a session with same key and same data, skipped.");
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Create a new entry */
|
||||
CHECK_MALLOC_DO( sr = malloc(sizeof(struct sr_data)), { ret = -1; goto out; } );
|
||||
memset(sr, 0, sizeof(struct sr_data));
|
||||
|
||||
fd_list_init(&sr->chain, sr);
|
||||
|
||||
CHECK_MALLOC_DO( sr->key.data = malloc(key.size), { ret = -1; goto out; } );
|
||||
sr->key.size = key.size;
|
||||
memcpy(sr->key.data, key.data, key.size);
|
||||
|
||||
CHECK_MALLOC_DO( sr->data.data = malloc(data.size), { ret = -1; goto out; } );
|
||||
sr->data.size = data.size;
|
||||
memcpy(sr->data.data, data.data, data.size);
|
||||
|
||||
/* Save this new entry in the list, we are done */
|
||||
fd_list_insert_before(li, &sr->chain);
|
||||
|
||||
out:
|
||||
CHECK_POSIX_DO( pthread_rwlock_unlock(&sto->lock), return -1 );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sr_remove (void *dbf, gnutls_datum_t key)
|
||||
{
|
||||
struct sr_store * sto = (struct sr_store *)dbf;
|
||||
struct fd_list * li;
|
||||
struct sr_data * sr;
|
||||
int match = 0;
|
||||
int ret = 0;
|
||||
|
||||
TRACE_DEBUG( GNUTLS_DBG_LEVEL, "GNUTLS Callback: %s", __PRETTY_FUNCTION__ );
|
||||
CHECK_PARAMS_DO( sto && key.data, return -1 );
|
||||
|
||||
CHECK_POSIX_DO( pthread_rwlock_wrlock(&sto->lock), return -1 );
|
||||
TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Session delete [key ", key.data, key.size, "]");
|
||||
|
||||
li = find_or_next(sto, key, &match);
|
||||
if (match) {
|
||||
sr = (struct sr_data *)li;
|
||||
|
||||
/* Destroy this data */
|
||||
fd_list_unlink(li);
|
||||
free(sr->key.data);
|
||||
free(sr->data.data);
|
||||
free(sr);
|
||||
} else {
|
||||
/* It was not found */
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
CHECK_POSIX_DO( pthread_rwlock_unlock(&sto->lock), return -1 );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gnutls_datum_t sr_fetch (void *dbf, gnutls_datum_t key)
|
||||
{
|
||||
struct sr_store * sto = (struct sr_store *)dbf;
|
||||
struct fd_list * li;
|
||||
struct sr_data * sr;
|
||||
int match = 0;
|
||||
gnutls_datum_t res = { NULL, 0 };
|
||||
gnutls_datum_t error = { NULL, 0 };
|
||||
|
||||
TRACE_DEBUG( GNUTLS_DBG_LEVEL, "GNUTLS Callback: %s", __PRETTY_FUNCTION__ );
|
||||
CHECK_PARAMS_DO( sto && key.data, return error );
|
||||
|
||||
CHECK_POSIX_DO( pthread_rwlock_rdlock(&sto->lock), return error );
|
||||
TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Session fetch [key ", key.data, key.size, "]");
|
||||
|
||||
li = find_or_next(sto, key, &match);
|
||||
if (match) {
|
||||
sr = (struct sr_data *)li;
|
||||
GNUTLS_TRACE( CHECK_MALLOC_DO(res.data = gnutls_malloc(sr->data.size), goto out ) );
|
||||
res.size = sr->data.size;
|
||||
memcpy(res.data, sr->data.data, res.size);
|
||||
}
|
||||
out:
|
||||
TRACE_DEBUG(GNUTLS_DBG_LEVEL, "Fetched (%p, %d) from store %p", res.data, res.size, sto);
|
||||
CHECK_POSIX_DO( pthread_rwlock_unlock(&sto->lock), return error);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Set the session pointer in a session object */
|
||||
static void set_resume_callbacks(gnutls_session_t session, struct cnxctx * conn)
|
||||
{
|
||||
TRACE_ENTRY("%p", conn);
|
||||
|
||||
GNUTLS_TRACE( gnutls_db_set_retrieve_function(session, sr_fetch));
|
||||
GNUTLS_TRACE( gnutls_db_set_remove_function (session, sr_remove));
|
||||
GNUTLS_TRACE( gnutls_db_set_store_function (session, sr_store));
|
||||
GNUTLS_TRACE( gnutls_db_set_ptr (session, conn->cc_sctp3436_data.sess_store));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* The handshake is made in parallel in several threads to speed up */
|
||||
static void * handshake_resume_th(void * arg)
|
||||
{
|
||||
struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) arg;
|
||||
int resumed;
|
||||
|
||||
TRACE_ENTRY("%p", arg);
|
||||
|
||||
/* Set the thread name */
|
||||
{
|
||||
char buf[48];
|
||||
snprintf(buf, sizeof(buf), "Handshake resume (%hu@%d)", ctx->strid, ctx->parent->cc_socket);
|
||||
fd_log_threadname ( buf );
|
||||
}
|
||||
|
||||
TRACE_DEBUG(FULL, "Starting TLS resumed handshake on stream %hu", ctx->strid);
|
||||
|
||||
CHECK_GNUTLS_DO( gnutls_handshake( ctx->session ), return NULL);
|
||||
|
||||
GNUTLS_TRACE( resumed = gnutls_session_is_resumed(ctx->session) );
|
||||
#ifndef GNUTLS_VERSION_300
|
||||
if (!resumed) {
|
||||
/* Check the credentials here also */
|
||||
CHECK_FCT_DO( fd_tls_verify_credentials(ctx->session, ctx->parent, 0), return NULL );
|
||||
}
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
if (TRACE_BOOL(FULL)) {
|
||||
if (resumed) {
|
||||
fd_log_debug("Session was resumed successfully on stream %hu (conn: '%s')", ctx->strid, fd_cnx_getid(ctx->parent));
|
||||
} else {
|
||||
fd_log_debug("Session was NOT resumed on stream %hu (full handshake) (conn: '%s')", ctx->strid, fd_cnx_getid(ctx->parent));
|
||||
}
|
||||
}
|
||||
|
||||
/* Finished, OK */
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************/
|
||||
/* Exported functions */
|
||||
/*************************************************************/
|
||||
|
||||
/* Initialize the wrapper for the connection */
|
||||
int fd_sctp3436_init(struct cnxctx * conn)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
TRACE_ENTRY("%p", conn);
|
||||
CHECK_PARAMS( conn && (conn->cc_sctp_para.pairs > 1) && (!conn->cc_sctp3436_data.array) );
|
||||
|
||||
/* First, alloc the array and initialize the non-TLS data */
|
||||
CHECK_MALLOC( conn->cc_sctp3436_data.array = calloc(conn->cc_sctp_para.pairs, sizeof(struct sctp3436_ctx)) );
|
||||
for (i = 0; i < conn->cc_sctp_para.pairs; i++) {
|
||||
conn->cc_sctp3436_data.array[i].parent = conn;
|
||||
conn->cc_sctp3436_data.array[i].strid = i;
|
||||
CHECK_FCT( fd_fifo_new(&conn->cc_sctp3436_data.array[i].raw_recv, 10) );
|
||||
}
|
||||
|
||||
/* Set push/pull functions in the master session, using fifo in array[0] */
|
||||
set_sess_transport(conn->cc_tls_para.session, &conn->cc_sctp3436_data.array[0]);
|
||||
|
||||
/* For server side, we also initialize the resuming capabilities */
|
||||
if (conn->cc_tls_para.mode == GNUTLS_SERVER) {
|
||||
|
||||
/* Prepare the store for sessions data */
|
||||
CHECK_FCT( store_init(conn) );
|
||||
|
||||
/* Set the callbacks for resuming in the master session */
|
||||
set_resume_callbacks(conn->cc_tls_para.session, conn);
|
||||
}
|
||||
|
||||
/* Start the demux thread */
|
||||
CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, demuxer, conn ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handshake other streams, after full handshake on the master session */
|
||||
int fd_sctp3436_handshake_others(struct cnxctx * conn, char * priority, void * alt_creds)
|
||||
{
|
||||
uint16_t i;
|
||||
int errors = 0;
|
||||
gnutls_datum_t master_data;
|
||||
|
||||
TRACE_ENTRY("%p %p", conn, priority);
|
||||
CHECK_PARAMS( conn && (conn->cc_sctp_para.pairs > 1) && conn->cc_sctp3436_data.array );
|
||||
|
||||
/* Server side: we set all the parameters, the resume callback will take care of resuming the session */
|
||||
/* Client side: we duplicate the parameters of the master session, then set the transport pointer */
|
||||
|
||||
/* For client side, retrieve the master session parameters */
|
||||
if (conn->cc_tls_para.mode == GNUTLS_CLIENT) {
|
||||
CHECK_GNUTLS_DO( gnutls_session_get_data2(conn->cc_tls_para.session, &master_data), return ENOMEM );
|
||||
/* For debug: */
|
||||
if (TRACE_BOOL(GNUTLS_DBG_LEVEL)) {
|
||||
uint8_t id[256];
|
||||
size_t ids = sizeof(id);
|
||||
CHECK_GNUTLS_DO( gnutls_session_get_id(conn->cc_tls_para.session, id, &ids), /* continue */ );
|
||||
TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Master session id: [", id, ids, "]");
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the session objects and start the handshake in a separate thread */
|
||||
for (i = 1; i < conn->cc_sctp_para.pairs; i++) {
|
||||
/* Set credentials and priority */
|
||||
CHECK_FCT( fd_tls_prepare(&conn->cc_sctp3436_data.array[i].session, conn->cc_tls_para.mode, 0, priority, alt_creds) );
|
||||
|
||||
/* additional initialization for gnutls 3.x */
|
||||
#ifdef GNUTLS_VERSION_300
|
||||
/* the verify function has already been set in the global initialization in config.c */
|
||||
|
||||
/* fd_tls_verify_credentials_2 uses the connection */
|
||||
gnutls_session_set_ptr (conn->cc_sctp3436_data.array[i].session, (void *) conn);
|
||||
|
||||
if ((conn->cc_tls_para.cn != NULL) && (conn->cc_tls_para.mode == GNUTLS_CLIENT)) {
|
||||
/* this might allow virtual hosting on the remote peer */
|
||||
CHECK_GNUTLS_DO( gnutls_server_name_set (conn->cc_sctp3436_data.array[i].session, GNUTLS_NAME_DNS, conn->cc_tls_para.cn, strlen(conn->cc_tls_para.cn)), /* ignore failure */);
|
||||
}
|
||||
|
||||
#endif /* GNUTLS_VERSION_300 */
|
||||
|
||||
#ifdef GNUTLS_VERSION_310
|
||||
GNUTLS_TRACE( gnutls_handshake_set_timeout( conn->cc_sctp3436_data.array[i].session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT));
|
||||
#endif /* GNUTLS_VERSION_310 */
|
||||
|
||||
/* For the client, copy data from master session; for the server, set session resuming pointers */
|
||||
if (conn->cc_tls_para.mode == GNUTLS_CLIENT) {
|
||||
CHECK_GNUTLS_DO( gnutls_session_set_data(conn->cc_sctp3436_data.array[i].session, master_data.data, master_data.size), return ENOMEM );
|
||||
} else {
|
||||
set_resume_callbacks(conn->cc_sctp3436_data.array[i].session, conn);
|
||||
}
|
||||
|
||||
/* Set transport parameters */
|
||||
set_sess_transport(conn->cc_sctp3436_data.array[i].session, &conn->cc_sctp3436_data.array[i]);
|
||||
|
||||
/* Start the handshake thread */
|
||||
CHECK_POSIX( pthread_create( &conn->cc_sctp3436_data.array[i].thr, NULL, handshake_resume_th, &conn->cc_sctp3436_data.array[i] ) );
|
||||
}
|
||||
|
||||
/* We can now release the memory of master session data if any */
|
||||
if (conn->cc_tls_para.mode == GNUTLS_CLIENT) {
|
||||
GNUTLS_TRACE( gnutls_free(master_data.data) );
|
||||
}
|
||||
|
||||
/* Now wait for all handshakes to finish */
|
||||
for (i = 1; i < conn->cc_sctp_para.pairs; i++) {
|
||||
void * ret;
|
||||
CHECK_POSIX( pthread_join(conn->cc_sctp3436_data.array[i].thr, &ret) );
|
||||
conn->cc_sctp3436_data.array[i].thr = (pthread_t) NULL;
|
||||
if (ret == NULL) {
|
||||
errors++; /* Handshake failed on this stream */
|
||||
}
|
||||
}
|
||||
|
||||
if (errors) {
|
||||
TRACE_DEBUG(INFO, "Handshake failed on %d/%hd stream pairs", errors, conn->cc_sctp_para.pairs);
|
||||
fd_cnx_markerror(conn);
|
||||
return ENOTCONN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Receive messages from others ? all other stream pairs : the master pair */
|
||||
int fd_sctp3436_startthreads(struct cnxctx * conn, int others)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
TRACE_ENTRY("%p", conn);
|
||||
CHECK_PARAMS( conn && conn->cc_sctp3436_data.array );
|
||||
|
||||
if (others) {
|
||||
for (i = 1; i < conn->cc_sctp_para.pairs; i++) {
|
||||
|
||||
/* Start the decipher thread */
|
||||
CHECK_POSIX( pthread_create( &conn->cc_sctp3436_data.array[i].thr, NULL, decipher, &conn->cc_sctp3436_data.array[i] ) );
|
||||
}
|
||||
} else {
|
||||
CHECK_POSIX( pthread_create( &conn->cc_sctp3436_data.array[0].thr, NULL, decipher, &conn->cc_sctp3436_data.array[0] ) );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initiate a "bye" on all stream pairs */
|
||||
void fd_sctp3436_bye(struct cnxctx * conn)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return );
|
||||
|
||||
/* End all TLS sessions, in series (not as efficient as paralel, but simpler) */
|
||||
for (i = 1; i < conn->cc_sctp_para.pairs; i++) {
|
||||
if ( ! fd_cnx_teststate(conn, CC_STATUS_ERROR)) {
|
||||
CHECK_GNUTLS_DO( gnutls_bye(conn->cc_sctp3436_data.array[i].session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* After "bye" was sent on all streams, read from sessions until an error is received */
|
||||
void fd_sctp3436_waitthreadsterm(struct cnxctx * conn)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
TRACE_ENTRY("%p", conn);
|
||||
CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return );
|
||||
|
||||
for (i = 0; i < conn->cc_sctp_para.pairs; i++) {
|
||||
if (conn->cc_sctp3436_data.array[i].thr != (pthread_t)NULL) {
|
||||
CHECK_POSIX_DO( pthread_join(conn->cc_sctp3436_data.array[i].thr, NULL), /* continue */ );
|
||||
conn->cc_sctp3436_data.array[i].thr = (pthread_t)NULL;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Free gnutls resources of all sessions */
|
||||
void fd_sctp3436_gnutls_deinit_others(struct cnxctx * conn)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
TRACE_ENTRY("%p", conn);
|
||||
CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return );
|
||||
|
||||
for (i = 1; i < conn->cc_sctp_para.pairs; i++) {
|
||||
if (conn->cc_sctp3436_data.array[i].session) {
|
||||
GNUTLS_TRACE( gnutls_deinit(conn->cc_sctp3436_data.array[i].session) );
|
||||
conn->cc_sctp3436_data.array[i].session = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Stop all receiver threads */
|
||||
void fd_sctp3436_stopthreads(struct cnxctx * conn)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
TRACE_ENTRY("%p", conn);
|
||||
CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return );
|
||||
|
||||
for (i = 0; i < conn->cc_sctp_para.pairs; i++) {
|
||||
CHECK_FCT_DO( fd_thr_term(&conn->cc_sctp3436_data.array[i].thr), /* continue */ );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Destroy a wrapper context */
|
||||
void fd_sctp3436_destroy(struct cnxctx * conn)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return );
|
||||
|
||||
/* Terminate all receiving threads in case we did not do it yet */
|
||||
fd_sctp3436_stopthreads(conn);
|
||||
|
||||
/* Now, stop the demux thread */
|
||||
CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ );
|
||||
|
||||
/* Free remaining data in the array */
|
||||
for (i = 0; i < conn->cc_sctp_para.pairs; i++) {
|
||||
if (conn->cc_sctp3436_data.array[i].raw_recv)
|
||||
fd_event_destroy( &conn->cc_sctp3436_data.array[i].raw_recv, free );
|
||||
free(conn->cc_sctp3436_data.array[i].partial.buf);
|
||||
if (conn->cc_sctp3436_data.array[i].session) {
|
||||
GNUTLS_TRACE( gnutls_deinit(conn->cc_sctp3436_data.array[i].session) );
|
||||
conn->cc_sctp3436_data.array[i].session = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the array itself now */
|
||||
free(conn->cc_sctp3436_data.array);
|
||||
conn->cc_sctp3436_data.array = NULL;
|
||||
|
||||
/* Delete the store of sessions */
|
||||
store_destroy(conn);
|
||||
|
||||
return ;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user