Commit ef546fbc authored by Sebastien Decugis's avatar Sebastien Decugis

Merge updates from Thomas (thanks\!)

parents 44682fb0 9774e196
......@@ -13,58 +13,13 @@
#define VENDOR_ID_3GPP 10415
/* The content of this file follows the same structure as dict_base_proto.c */
#if 0
#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) );
#endif
void dump_sess_eyec(struct session *sess, const char *);
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_ }}}
static int ccr_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
static int reauth_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
static int cca_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
......@@ -287,7 +242,7 @@ static int app_gx_entry(char * conffile)
CHECK_FCT( fd_event_trig_regcb(SIGUSR1, "app_gx", sig_hdlr ) );
TRACE_DEBUG(INFO, "Extension 'Dictionary definitions for DCCA (rfc4006)' initialized");
TRACE_DEBUG(INFO, "Extension 'Gx' initialized");
return 0;
}
......@@ -860,5 +815,5 @@ static int gx_entry(char * conffile)
{
return 0;
}
EXTENSION_ENTRY( "app_gx", app_gx_entry, "dict_dcca");
EXTENSION_ENTRY( "app_gx", app_gx_entry, "dict_dcca_3gpp");
//EXTENSION_ENTRY( "app_gx", gx_entry);
......@@ -67,12 +67,13 @@ FD_EXTENSION_SUBDIR(app_redirect "Diameter Redirect server: send configurable Re
####
# Routing extensions
FD_EXTENSION_SUBDIR(rt_default "Configurable routing rules for freeDiameter" ON)
FD_EXTENSION_SUBDIR(rt_redirect "Handling of Diameter Redirect messages" ON)
FD_EXTENSION_SUBDIR(rt_busypeers "Handling of Diameter TOO_BUSY messages and relay timeouts" ON)
FD_EXTENSION_SUBDIR(rt_default "Configurable routing rules for freeDiameter" ON)
FD_EXTENSION_SUBDIR(rt_ereg "Configurable routing based on regexp matching of AVP values" OFF)
FD_EXTENSION_SUBDIR(rt_ignore_dh "Stow Destination-Host in Proxy-Info, restore to Origin-Host for answers" ON)
FD_EXTENSION_SUBDIR(rt_load_balance "Balance load over multiple equal hosts, based on outstanding requests" ON)
FD_EXTENSION_SUBDIR(rt_randomize "Randomly choose one of the highest scored hosts and increase its score by one" ON)
FD_EXTENSION_SUBDIR(rt_redirect "Handling of Diameter Redirect messages" ON)
####
......
......@@ -87,10 +87,12 @@ static int dict_dcca_starent_entry(char * conffile)
/* The following is created automatically. Do not modify. */
/* Changes will be lost during the next update. Modify the source org file instead. */
/* Cisco ASR 5000 Series AAA Interface */
/* Administration and Reference */
/* Release 8.x and 9.0 */
/* Last Updated June 30, 2010 */
/* Cisco ASR 5000 Series AAA Interface */
/* Administration and Reference */
/* Release 8.x and 9.0 */
/* Last Updated June 30, 2010 */
/* updated using v15 docs from Jan 2014 */
/* www.cisco.com/c/dam/en/us/td/docs/wireless/asr_5000/15-0/15-0-AAA-Reference.pdf */
/* SN-Volume-Quota-Threshold */
{
struct dict_avp_data data = {
......@@ -282,9 +284,159 @@ static int dict_dcca_starent_entry(char * conffile)
CHECK_dict_new(DICT_AVP, &data, type, NULL);
};
/* SN-Session-Start-Indicator */
{
struct dict_avp_data data = {
522, /* Code */
8164, /* Vendor */
"SN-Session-Start-Indicator", /* 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);
};
/* SN-Phase0-PSAPName */
{
struct dict_avp_data data = {
523, /* Code */
8164, /* Vendor */
"SN-Phase0-PSAPName", /* Name */
AVP_FLAG_VENDOR, /* Fixed flags */
AVP_FLAG_VENDOR, /* Fixed flag values */
AVP_TYPE_OCTETSTRING /* base type of data */
};
CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
};
/* SN-Charging-Id */
{
struct dict_avp_data data = {
525, /* Code */
8164, /* Vendor */
"SN-Charging-Id", /* Name */
AVP_FLAG_VENDOR, /* Fixed flags */
AVP_FLAG_VENDOR, /* Fixed flag values */
AVP_TYPE_OCTETSTRING /* base type of data */
};
CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
};
/* SN-Remaining-Service-Unit */
{
struct dict_avp_data data = {
526, /* Code */
8164, /* Vendor */
"SN-Remaining-Service-Unit", /* Name */
AVP_FLAG_VENDOR, /* Fixed flags */
AVP_FLAG_VENDOR, /* Fixed flag values */
AVP_TYPE_GROUPED /* base type of data */
};
CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
};
/* SN-Service-Start-Timestamp */
{
struct dict_avp_data data = {
527, /* Code */
8164, /* Vendor */
"SN-Service-Start-Timestamp", /* Name */
AVP_FLAG_VENDOR, /* Fixed flags */
AVP_FLAG_VENDOR, /* Fixed flag values */
AVP_TYPE_OCTETSTRING /* base type of data */
};
CHECK_dict_new(DICT_AVP, &data, Time_type, NULL);
};
/* SN-Rulebase-Id */
{
struct dict_avp_data data = {
528, /* Code */
8164, /* Vendor */
"SN-Rulebase-Id", /* 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);
};
/* SN-CF-Policy-ID */
{
struct dict_avp_data data = {
529, /* Code */
8164, /* Vendor */
"SN-CF-Policy-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);
};
/* SN-Charging-Collection-Function-Name */
{
struct dict_avp_data data = {
530, /* Code */
8164, /* Vendor */
"SN-Charging-Collection-Function-Name", /* Name */
AVP_FLAG_VENDOR, /* Fixed flags */
AVP_FLAG_VENDOR, /* Fixed flag values */
AVP_TYPE_OCTETSTRING /* base type of data */
};
CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
};
/* SN-Fast-Reauth-Username */
{
struct dict_avp_data data = {
11010, /* Code */
8164, /* Vendor */
"SN-Fast-Reauth-Username", /* 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);
};
/* SN-Pseudonym-Username */
{
struct dict_avp_data data = {
11011, /* Code */
8164, /* Vendor */
"SN-Pseudonym-Username", /* 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);
};
/* Rules section */
/* SN-Remaining-Service-Unit */
{
struct dict_object *rule_avp;
struct dict_avp_request vpa;
vpa.avp_vendor = 8164;
vpa.avp_name = "SN-Remaining-Service-Unit";
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
struct local_rules_definition rules[] = {
{ "Tariff-Change-Usage", RULE_OPTIONAL, -1, 1 },
{ "CC-Time", RULE_OPTIONAL, -1, 1 },
{ "CC-Total-Octets", RULE_OPTIONAL, -1, 1 },
{ "CC-Input-Octets", RULE_OPTIONAL, -1, 1 },
{ "CC-Output-Octets", RULE_OPTIONAL, -1, 1 },
{ "CC-Service-Specific-Units", RULE_OPTIONAL, -1, 1 },
{ "Reporting-Reason", RULE_OPTIONAL, -1, 1 }
};
PARSE_loc_rules( rules, rule_avp );
}
/* SN-Total-Used-Service-Unit */
{
struct dict_object *rule_avp;
......
| Attribute Name | Code | Section defined | Value Type | MUST | MAY | SHLD NOT | MUST NOT | Encr |
| # Cisco ASR 5000 Series AAA Interface | | | | | | | | |
| # Administration and Reference | | | | | | | | |
| # Release 8.x and 9.0 | | | | | | | | |
| # Last Updated June 30, 2010 | | | | | | | | |
| SN-Volume-Quota-Threshold | 501 | | Unsigned32 | M,V | | | | |
| SN-Unit-Quota-Threshold | 502 | | Unsigned32 | M,V | | | | |
| SN-Time-Quota-Threshold | 503 | | Unsigned32 | M,V | | | | |
| SN-Total-Used-Service-Unit | 504 | | Grouped | V | | | | |
| SN-Absolute-Validity-Time | 505 | | Time | V | | | | |
| SN-Bandwidth-Control | 512 | | Enumerated | M,V | | | | |
| SN-Transparent-Data | 513 | | OctetString | V | | | | |
| SN-Traffic-Policy | 514 | | UTF8String | V | | | | |
| SN-Firewall-Policy | 515 | | UTF8String | V | | | | |
| SN-Usage-Monitoring-Control | 517 | | Grouped | V | | | | |
| SN-Monitoring-Key | 518 | | Unsigned32 | V | | | | |
| SN-Usage-Volume | 519 | | Unsigned64 | V | | | | |
| SN-Service-Flow-Detection | 520 | | Enumerated | V | | | | |
| SN-Usage-Monitoring | 521 | | Enumerated | V | | | | |
| Attribute Name | Code | Section defined | Value Type | MUST | MAY | SHLD NOT | MUST NOT | Encr |
| # Cisco ASR 5000 Series AAA Interface | | | | | | | | |
| # Administration and Reference | | | | | | | | |
| # Release 8.x and 9.0 | | | | | | | | |
| # Last Updated June 30, 2010 | | | | | | | | |
| # updated using v15 docs from Jan 2014 | | | | | | | | |
| # www.cisco.com/c/dam/en/us/td/docs/wireless/asr_5000/15-0/15-0-AAA-Reference.pdf | | | | | | | | |
| SN-Volume-Quota-Threshold | 501 | | Unsigned32 | M,V | | | | |
| SN-Unit-Quota-Threshold | 502 | | Unsigned32 | M,V | | | | |
| SN-Time-Quota-Threshold | 503 | | Unsigned32 | M,V | | | | |
| SN-Total-Used-Service-Unit | 504 | | Grouped | V | | | | |
| SN-Absolute-Validity-Time | 505 | | Time | V | | | | |
| SN-Bandwidth-Control | 512 | | Enumerated | M,V | | | | |
| SN-Transparent-Data | 513 | | OctetString | V | | | | |
| SN-Traffic-Policy | 514 | | UTF8String | V | | | | |
| SN-Firewall-Policy | 515 | | UTF8String | V | | | | |
| SN-Usage-Monitoring-Control | 517 | | Grouped | V | | | | |
| SN-Monitoring-Key | 518 | | Unsigned32 | V | | | | |
| SN-Usage-Volume | 519 | | Unsigned64 | V | | | | |
| SN-Service-Flow-Detection | 520 | | Enumerated | V | | | | |
| SN-Usage-Monitoring | 521 | | Enumerated | V | | | | |
| SN-Session-Start-Indicator | 522 | | OctetString | M,V | | | | |
| SN-Phase0-PSAPName | 523 | | UTF8String | V | | | | |
| SN-Charging-Id | 525 | | OctetString | V | | | | |
| SN-Remaining-Service-Unit | 526 | | Grouped | V | | | | |
| SN-Service-Start-Timestamp | 527 | | Time | V | | | | |
| SN-Rulebase-Id | 528 | | UTF8String | M,V | | | | |
| SN-CF-Policy-ID | 529 | | Unsigned32 | M,V | | | | |
| SN-Charging-Collection-Function-Name | 530 | | UTF8String | V | | | | |
| SN-Fast-Reauth-Username | 11010 | | OctetString | M,V | | | | |
| SN-Pseudonym-Username | 11011 | | OctetString | M,V | | | | |
......@@ -49,7 +49,7 @@ int rt_busy_process_busy(struct msg ** pmsg, int is_req, DiamId_t sentto, size_t
struct msg * qry = NULL;
struct rt_data * rtd = NULL;
struct fd_list * candidates = NULL;
int sendingattemtps;
int sendingattempts;
int resend = 1;
......@@ -72,13 +72,13 @@ int rt_busy_process_busy(struct msg ** pmsg, int is_req, DiamId_t sentto, size_t
(uint8_t *)(oh ? (DiamId_t)oh->os.data : fd_g_config->cnf_diamid), oh ? oh->os.len : fd_g_config->cnf_diamid_len ,
ER_DIAMETER_TOO_BUSY,
&candidates,
&sendingattemtps) );
&sendingattempts) );
/* Now we need to decide if we re-send this query to a different peer or return an error to upstream */
/* First, are we exceeding the allowed attempts? */
if (rtbusy_conf.RetryMaxPeers != 0) {
if (sendingattemtps >= rtbusy_conf.RetryMaxPeers) {
if (sendingattempts >= rtbusy_conf.RetryMaxPeers) {
TRACE_DEBUG(FULL, "Maximum number of sending attempts reached for message %p, returning an error upstream", qry);
resend = 0;
}
......@@ -106,10 +106,16 @@ int rt_busy_process_busy(struct msg ** pmsg, int is_req, DiamId_t sentto, size_t
}
/* Send the query again. We need to re-associate the expirecb which was cleaned, if it is used */
if (rtbusy_conf.RelayTimeout) {
char *buf = NULL;
size_t len;
struct timespec expire;
CHECK_SYS( clock_gettime(CLOCK_REALTIME, &expire) );
expire.tv_sec += rtbusy_conf.RelayTimeout/1000 + ((expire.tv_nsec + (1000000LL * (rtbusy_conf.RelayTimeout % 1000))) / 1000000000LL);
expire.tv_nsec = (expire.tv_nsec + (1000000LL * (rtbusy_conf.RelayTimeout % 1000))) % 1000000000LL;
CHECK_MALLOC_DO( fd_msg_dump_full(&buf, &len, NULL, *pmsg, fd_g_config->cnf_dict, 0, 1), /* nothing */);
TRACE_ERROR( "No answer received for message from peer '%.*s' before timeout (%dms), re-sending: %s", senttolen, sentto,
rtbusy_conf.RelayTimeout, buf);
free(buf);
CHECK_FCT( fd_msg_send_timeout( pmsg, NULL, NULL, rtbusy_expirecb, &expire ) );
} else {
CHECK_FCT( fd_msg_send(pmsg, NULL, NULL) );
......@@ -117,6 +123,13 @@ int rt_busy_process_busy(struct msg ** pmsg, int is_req, DiamId_t sentto, size_t
} else {
if (is_req) {
char *buf = NULL;
size_t len;
CHECK_MALLOC_DO( fd_msg_dump_full(&buf, &len, NULL, *pmsg, fd_g_config->cnf_dict, 0, 1), /* nothing */);
TRACE_ERROR( "No answer received for message from peer '%.*s' before timeout (%dms), giving up and sending error reply: %s", senttolen, sentto,
rtbusy_conf.RelayTimeout, buf);
free(buf);
/* We must create an answer */
CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, pmsg, MSGFL_ANSW_ERROR ) );
......
......@@ -42,15 +42,6 @@ struct dict_object * ph_avp_do; /* cache the Proxy-Host dictionary object */
struct dict_object * pi_avp_do; /* cache the Proxy-Info dictionary object */
struct dict_object * ps_avp_do; /* cache the Proxy-State dictionary object */
static void *memdup(void *data, size_t len)
{
void *mem;
if ((mem=malloc(len)) == NULL)
return NULL;
memcpy(mem, data, len);
return mem;
}
static int restore_origin_host(struct msg **msg) {
struct avp *avp, *child;
struct avp *oh_avp = NULL;
......@@ -91,12 +82,8 @@ static int restore_origin_host(struct msg **msg) {
}
break;
case AC_PROXY_STATE:
ps = chdr->avp_value->os.data;
ps_len = chdr->avp_value->os.len;
ps = memdup(chdr->avp_value->os.data, ps_len);
if (!ps) {
TRACE_ERROR("malloc failure");
return 0;
}
break;
default:
break;
......@@ -108,8 +95,7 @@ static int restore_origin_host(struct msg **msg) {
new_oh = ps;
new_oh_len = ps_len;
pi_avp = avp;
} else
free(ps);
}
break;
default:
break;
......@@ -151,13 +137,13 @@ static int stow_destination_host(struct msg **msg) {
/* add Proxy-Info->{Proxy-Host, Proxy-State} using Destination-Host information */
CHECK_FCT(fd_msg_avp_new(ph_avp_do, 0, &ph_avp));
memset(&val, 0, sizeof(val));
val.os.data = memdup(fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len);
val.os.data = fd_g_config->cnf_diamid;
val.os.len = fd_g_config->cnf_diamid_len;
CHECK_FCT(fd_msg_avp_setvalue(ph_avp, &val));
CHECK_FCT(fd_msg_avp_new(ps_avp_do, 0, &ps_avp));
memset(&val, 0, sizeof(val));
val.os.data = memdup(ahdr->avp_value->os.data, ahdr->avp_value->os.len);
val.os.data = ahdr->avp_value->os.data;
val.os.len = ahdr->avp_value->os.len;
CHECK_FCT(fd_msg_avp_setvalue(ps_avp, &val));
......
......@@ -2,14 +2,14 @@
PROJECT("Routing extension splits requests evenly over multiple hosts, using current load as routing indicator" C)
# List of source files
SET(RT_IGNORE_DH_SRC
SET(RT_LOAD_BALANCE_SRC
rt_load_balance.c
)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
# Compile these files as a freeDiameter extension
FD_ADD_EXTENSION(rt_load_balance ${RT_IGNORE_DH_SRC})
FD_ADD_EXTENSION(rt_load_balance ${RT_LOAD_BALANCE_SRC})
####
## INSTALL section ##
......
......@@ -2,7 +2,7 @@
* Software License Agreement (BSD License) *
* Author: Thomas Klausner <tk@giga.or.at> *
* *
* Copyright (c) 2013, Thomas Klausner *
* Copyright (c) 2013, 2014 Thomas Klausner *
* All rights reserved. *
* *
* Written under contract by nfotex IT GmbH, http://nfotex.com/ *
......@@ -58,12 +58,18 @@ static int rt_load_balancing(void * cbdata, struct msg ** pmsg, struct fd_list *
CHECK_FCT(fd_peer_getbyid(cand->diamid, cand->diamidlen, 0, &peer));
CHECK_FCT(fd_peer_get_load_pending(peer, &to_receive, &to_send));
load = to_receive + to_send;
score = cand->score;
if ((cand->score > 0) && (load >= cand->score))
cand->score = 1;
else
cand->score -= load;
TRACE_DEBUG(INFO, "evaluated peer `%.*s', score was %d, now %d", (int)cand->diamidlen, cand->diamid, score, cand->score);
/* other routing mechanisms need to add to the
* appropriate entries so their base value is high
* enough that they are considered */
/* logarithmic scaling */
int load_log = 0;
while (load > 0) {
load_log++;
load /= 2;
}
cand->score -= load_log;
TRACE_DEBUG(FULL, "evaluated peer `%.*s', score was %d, now %d", (int)cand->diamidlen, cand->diamid, score, cand->score);
}
return 0;
......
# The rt_randomize extension
PROJECT("Routing extension randomly increases the routing count for one of the highest-rated hosts, if there are multiple ones" C)
# List of source files
SET(RT_RANDOMIZE_SRC
rt_randomize.c
)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
# Compile these files as a freeDiameter extension
FD_ADD_EXTENSION(rt_randomize ${RT_RANDOMIZE_SRC})
####
## INSTALL section ##
# We install with the daemon component because it is a base feature.
INSTALL(TARGETS rt_randomize
LIBRARY DESTINATION ${INSTALL_EXTENSIONS_SUFFIX}
COMPONENT freeDiameter-daemon)
/*********************************************************************************************************
* Software License Agreement (BSD License) *
* Author: Thomas Klausner <tk@giga.or.at> *
* *
* Copyright (c) 2014 Thomas Klausner *
* All rights reserved. *
* *
* Written under contract by nfotex IT GmbH, http://nfotex.com/ *
* *
* 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. *
* *
* 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/extension.h>
/*
* Load balancing extension. If there are multiple highest-rated hosts with the same score,
* randomly increase the score of one of them.
*/
#include <stdlib.h>
static int seed;
static int rt_randomizing(void * cbdata, struct msg ** pmsg, struct fd_list * candidates)
{
struct fd_list *lic;
struct msg * msg = *pmsg;
int max_score = -1;
int max_score_count = 0;
TRACE_ENTRY("%p %p %p", cbdata, msg, candidates);
CHECK_PARAMS(msg && candidates);
/* Check if it is worth processing the message */
if (FD_IS_LIST_EMPTY(candidates))
return 0;
/* find out maximal score and how many candidates have it */
for (lic = candidates->next; lic != candidates; lic = lic->next) {
struct rtd_candidate * cand = (struct rtd_candidate *) lic;
if (max_score < cand->score) {
max_score = cand->score;
max_score_count = 1;
}
else if (cand->score == max_score) {
max_score_count++;
}
}
/* if there is more than one with positive score, randomly increase one of their scores by one */
if (max_score >= 0 && max_score_count > 1) {
int lucky_candidate = rand_r(&seed) % max_score_count;
int i = 0;
for (lic = candidates->next; lic != candidates; lic = lic->next) {
struct rtd_candidate * cand = (struct rtd_candidate *) lic;
if (cand->score == max_score) {
if (i == lucky_candidate) {
cand->score++;
break;
}
i++;
}
}
}
return 0;
}
/* handler */
static struct fd_rt_out_hdl * rt_randomizing_hdl = NULL;
/* entry point */
static int rt_randomize_entry(char * conffile)
{
/* Register the callback */
CHECK_FCT(fd_rt_out_register(rt_randomizing, NULL, 4, &rt_randomizing_hdl));
seed = (int)time(NULL);
TRACE_DEBUG(INFO, "Extension 'Randomizing' initialized");
return 0;
}
/* Unload */