Mercurial > hg > freeDiameter
changeset 168:6db078b955e3
Completed rt_default extension
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Tue, 02 Feb 2010 10:15:05 +0900 |
parents | 967e579beb64 |
children | f8507f57a3c0 |
files | doc/rt_default.conf.sample extensions/rt_default/CMakeLists.txt extensions/rt_default/rt_default-host.h.in extensions/rt_default/rt_default.c extensions/rt_default/rt_default.h extensions/rt_default/rtd_conf.l extensions/rt_default/rtd_conf.y extensions/rt_default/rtd_rules.c freeDiameter/routing_dispatch.c include/freeDiameter/CMakeLists.txt include/freeDiameter/libfreeDiameter.h libfreeDiameter/rt_data.c |
diffstat | 12 files changed, 593 insertions(+), 31 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/rt_default.conf.sample Fri Jan 29 18:57:40 2010 +0900 +++ b/doc/rt_default.conf.sample Tue Feb 02 10:15:05 2010 +0900 @@ -44,15 +44,15 @@ # - 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, or -# - a bracket-quoted string ["some regex"] that will be interpreted as a POSIX regular expression, and attempt to match the string. +# - 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 +# 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 @@ -60,8 +60,8 @@ # si="STR/REG" -> idem with Session-Id # # The TARGET is also of a similar form: -# i="STR/REG" -> Will apply the score to this peer if its Diameter-Id is matched by the string or regular expression. -# r="STR/REG" -> Idem with the peer's advertized Diameter-Realm. +# "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 freeDiameter.h): # NO_DELIVERY @@ -78,14 +78,14 @@ # # # Here are some examples: -# 1) Rule to add a default next-hop to all messages: -# * : i="proxy.testbed.aaa" += DEFAULT ; +# 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" : r="realmB" += DEFAULT_REALM ; +# dr="realmA" : rlm="realmB" += DEFAULT_REALM ; # # 3) Avoid sending messages with decorated NAI to the proxy A: -# un=[".+!.+@.+"] : i="proxy.A" += NO_DELIVERY ; +# un=[".+!.+@.+"] : "proxy.A" += NO_DELIVERY ;
--- a/extensions/rt_default/CMakeLists.txt Fri Jan 29 18:57:40 2010 +0900 +++ b/extensions/rt_default/CMakeLists.txt Tue Feb 02 10:15:05 2010 +0900 @@ -1,6 +1,18 @@ # The rt_default extension PROJECT("Configurable routing extension" C) +# Check if REG_STARTEND is provided on the host +SET(CHECK_REG_STARTEND_SOURCE_CODE " + #include <unistd.h> + #include <regex.h> + int main() { + return regexec(NULL, NULL, 0, NULL, REG_STARTEND); + } + ") +CHECK_C_SOURCE_COMPILES("${CHECK_REG_STARTEND_SOURCE_CODE}" HAVE_REG_STARTEND) +# Generate the host.h file +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/rt_default-host.h.in ${CMAKE_CURRENT_BINARY_DIR}/rt_default-host.h) + # Parser files BISON_FILE(rtd_conf.y) FLEX_FILE(rtd_conf.l) @@ -16,5 +28,7 @@ rtd_rules.c ) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) + # Compile these files as a freeDiameter extension FD_ADD_EXTENSION(rt_default ${RT_DEFAULT_SRC})
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/rt_default/rt_default-host.h.in Tue Feb 02 10:15:05 2010 +0900 @@ -0,0 +1,42 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis <sdecugis@nict.go.jp> * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +/* Configuration from compile-time */ +#ifndef RTD_IS_CONFIG +#define RTD_IS_CONFIG + +#cmakedefine HAVE_REG_STARTEND + +#endif /* RTD_IS_CONFIG */
--- a/extensions/rt_default/rt_default.c Fri Jan 29 18:57:40 2010 +0900 +++ b/extensions/rt_default/rt_default.c Tue Feb 02 10:15:05 2010 +0900 @@ -68,7 +68,7 @@ /* Parse the configuration file */ CHECK_FCT( rtd_conf_handle(conffile) ); -#if 1 +#if 0 /* Dump the rules */ rtd_dump(); #endif /* 0 */
--- a/extensions/rt_default/rt_default.h Fri Jan 29 18:57:40 2010 +0900 +++ b/extensions/rt_default/rt_default.h Tue Feb 02 10:15:05 2010 +0900 @@ -38,8 +38,12 @@ * See the rt_default.conf.sample file for the format of the configuration file. */ +/* FreeDiameter's common include file */ #include <freeDiameter/extension.h> +/* Host configuration for this specific extension */ +#include <rt_default-host.h> + /* Parse the configuration file */ int rtd_conf_handle(char * conffile);
--- a/extensions/rt_default/rtd_conf.l Fri Jan 29 18:57:40 2010 +0900 +++ b/extensions/rt_default/rtd_conf.l Tue Feb 02 10:15:05 2010 +0900 @@ -132,8 +132,7 @@ (?i:"dr") { return DR; } (?i:"un") { return UN; } (?i:"si") { return SI; } -(?i:"i") { return IDENTITY;} -(?i:"r") { return REALM; } +(?i:"rlm") { return REALM; } /* Valid single characters for yyparse */ [*:=+;] { return yytext[0]; }
--- a/extensions/rt_default/rtd_conf.y Fri Jan 29 18:57:40 2010 +0900 +++ b/extensions/rt_default/rtd_conf.y Tue Feb 02 10:15:05 2010 +0900 @@ -151,7 +151,6 @@ %token UN %token SI -%token IDENTITY %token REALM @@ -179,6 +178,8 @@ yyerror (&yylloc, conffile, "An error occurred while adding a rule, aborting..."); YYERROR; } ); + + rules_added++; } ; @@ -241,10 +242,10 @@ ; /* Details of the TARGET type */ -TARGET: IDENTITY '=' TSTRING +TARGET: TSTRING { - $$.str = $3.str; - $$.regex =$3.regex; + $$.str = $1.str; + $$.regex =$1.regex; $$.type = RTD_TAR_ID; } | REALM '=' TSTRING
--- a/extensions/rt_default/rtd_rules.c Fri Jan 29 18:57:40 2010 +0900 +++ b/extensions/rt_default/rtd_rules.c Tue Feb 02 10:15:05 2010 +0900 @@ -49,65 +49,562 @@ * Note: Except during configuration parsing and module termination, the lists are only ever accessed read-only, so we do not need a lock. */ -/* Structure to hold the data that is used for matching. Note that in case is_regex is true, the string to be matched must be \0-terminated. */ +/* Structure to hold the data that is used for matching. */ struct match_data { int is_regex; /* determines how the string is matched */ char *plain; /* match this value with strcasecmp if is_regex is false. The string is allocated by the lex tokenizer, must be freed at the end. */ regex_t preg; /* match with regexec if is_regex is true. regfree must be called at the end. A copy of the original string is anyway saved in plain. */ }; +/* The sentinels for the TARGET lists */ +static struct fd_list TARGETS[RTD_TAR_MAX]; + /* Structure of a TARGET element */ struct target { - struct fd_list chain; /* link in the top-level list */ - struct match_data md; /* the data to determine if the current candidate matches this element */ - struct fd_list rules; /* Sentinel for the list of rules applying to this target */ + struct fd_list chain; /* link in the top-level list */ + struct match_data md; /* the data to determine if the current candidate matches this element */ + struct fd_list rules[RTD_CRI_MAX]; /* Sentinels for the lists of rules applying to this target. One list per rtd_crit_type */ /* note : we do not need the rtd_targ_type here, it is implied by the root of the list this target element is attached to */ }; /* Structure of a RULE element */ struct rule { struct fd_list chain; /* link in the parent target list */ - enum rtd_crit_type type; /* What kind of criteria the message must match for the rule to apply */ - struct match_data md; /* the data that the criteria must match, if it is different from RTD_CRI_ALL */ + struct match_data md; /* the data that the criteria must match, -- ignored for RTD_CRI_ALL */ int score; /* The score added to the candidate, if the message matches this criteria */ + /* The type of rule depends on the sentinel */ }; -/* The sentinels for the TARGET lists */ -static struct fd_list TARGETS[RTD_TAR_MAX]; +/*********************************************************************/ + +/* Compile a regular expression pattern */ +static int compile_regex( regex_t * preg, char * str ) +{ + int err; + + /* Compile the regular expression */ + err = regcomp(preg, str, REG_EXTENDED | REG_NOSUB); + if (err != 0) { + char * buf; + size_t bl; + + /* Error while compiling the regex */ + TRACE_DEBUG(INFO, "Error while compiling the regular expression '%s':", str); + + /* Get the error message size */ + bl = regerror(err, preg, NULL, 0); + + /* Alloc the buffer for error message */ + CHECK_MALLOC( buf = malloc(bl) ); + + /* Get the error message content */ + regerror(err, preg, buf, bl); + TRACE_DEBUG(INFO, "\t%s", buf); + + /* Free the buffer, return the error */ + free(buf); + return EINVAL; + } + + return 0; +} + +/* Create a target item and initialize its content */ +static struct target * new_target(char * str, int regex) +{ + int i; + struct target *new = NULL; + CHECK_MALLOC_DO( new = malloc(sizeof(struct target)), return NULL ); + memset(new, 0, sizeof(struct target)); + + fd_list_init(&new->chain, new); + new->md.plain = str; + new->md.is_regex = regex; + if (regex) { + CHECK_FCT_DO( compile_regex(&new->md.preg, str), + { + free(new); + return NULL; + } ); + } + for (i = 0; i < RTD_CRI_MAX; i++) { + fd_list_init(&new->rules[i], new); + } + return new; +} + +/* Create a rule item and initialize its content; return NULL in case of error */ +static struct rule * new_rule(char * str, int regex, int score) +{ + struct rule *new = NULL; + CHECK_MALLOC_DO( new = malloc(sizeof(struct rule)), return NULL ); + memset(new, 0, sizeof(struct rule)); + + fd_list_init(&new->chain, new); + new->md.plain = str; + new->md.is_regex = regex; + if (regex) { + CHECK_FCT_DO( compile_regex(&new->md.preg, str), + { + free(new); + return NULL; + } ); + } + new->score = score; + return new; +} + +/* Debug functions */ +static void dump_rule(int indent, struct rule * rule) +{ + fd_log_debug("%*s%s%s%s += %d\n", + indent, "", + rule->md.is_regex ? "[" : "'", + rule->md.plain, + rule->md.is_regex ? "]" : "'", + rule->score); +} +static void dump_target(int indent, struct target * target) +{ + int i; + fd_log_debug("%*s%s%s%s :\n", + indent, "", + target->md.is_regex ? "[" : "'", + target->md.plain ?: "(empty)", + target->md.is_regex ? "]" : "'"); + for (i = 0; i < RTD_CRI_MAX; i++) { + if (! FD_IS_LIST_EMPTY(&target->rules[i])) { + struct fd_list * li; + fd_log_debug("%*s rules[%d]:\n", + indent, "", i); + for (li = target->rules[i].next; li != &target->rules[i]; li = li->next) { + dump_rule(indent + 3, (struct rule *)li); + } + } + } +} + +static void clear_md(struct match_data * md) +{ + /* delete the string */ + if (md->plain) { + free(md->plain); + md->plain = NULL; + } + + /* delete the preg if needed */ + if (md->is_regex) { + regfree(&md->preg); + md->is_regex = 0; + } +} + +/* Destroy a rule item */ +static void del_rule(struct rule * del) +{ + /* Unlink this rule */ + fd_list_unlink(&del->chain); + + /* Delete the match data */ + clear_md(&del->md); + + free(del); +} + +/* Destroy a target item, and all its rules */ +static void del_target(struct target * del) +{ + int i; + + /* Unlink this target */ + fd_list_unlink(&del->chain); + + /* Delete the match data */ + clear_md(&del->md); + + /* Delete the children rules */ + for (i = 0; i < RTD_CRI_MAX; i++) { + while (! FD_IS_LIST_EMPTY(&del->rules[i]) ) { + del_rule((struct rule *)(del->rules[i].next)); + } + } + + free(del); +} +/* Compare a string with a match_data value. *res contains the result of the comparison (always >0 for regex non-match situations) */ +static int compare_match(char * str, size_t len, struct match_data * md, int * res) +{ + int err; + + CHECK_PARAMS( str && md && res ); + + /* Plain strings: we compare with strncasecmp */ + if (md->is_regex == 0) { + *res = strncasecmp(str, md->plain, len); + return 0; + } + /* Regexp */ + *res = 1; + +#ifdef HAVE_REG_STARTEND + { + regmatch_t pmatch[1]; + memset(pmatch, 0, sizeof(pmatch)); + pmatch[0].rm_so = 0; + pmatch[0].rm_eo = len; + err = regexec(&md->preg, str, 0, pmatch, REG_STARTEND); + } +#else /* HAVE_REG_STARTEND */ + { + /* We have to create a copy of the string in this case */ + char *mystrcpy; + CHECK_MALLOC( mystrcpy = malloc(len + 1) ); + memcpy(mystrcpy, str, len); + mystrcpy[len] = '\0'; + err = regexec(&md->preg, mystrcpy, 0, NULL, 0); + free(mystrcpy); + } +#endif /* HAVE_REG_STARTEND */ + + /* Now check the result */ + if (err == 0) { + /* We have a match */ + *res = 0; + return 0; + } + + if (err == REG_NOMATCH) { + *res = 1; + return 0; + } + + /* In other cases, we have an error */ + { + char * buf; + size_t bl; + + /* Error while compiling the regex */ + TRACE_DEBUG(INFO, "Error while executing the regular expression '%s':", md->plain); + + /* Get the error message size */ + bl = regerror(err, &md->preg, NULL, 0); + + /* Alloc the buffer for error message */ + CHECK_MALLOC( buf = malloc(bl) ); + + /* Get the error message content */ + regerror(err, &md->preg, buf, bl); + TRACE_DEBUG(INFO, "\t%s", buf); + + /* Free the buffer, return the error */ + free(buf); + } + + return (err == REG_ESPACE) ? ENOMEM : EINVAL; +} + +/* Search in list (targets or rules) the next matching item for string str(len). Returned in next_match, or *next_match == NULL if no more match. Re-enter with same next_match for the next one. */ +static int get_next_match(struct fd_list * list, char * str, size_t len, struct fd_list ** next_match) +{ + struct fd_list * li; + + TRACE_ENTRY("%p %p %zd %p", list, str, len, next_match); + CHECK_PARAMS(list && str && len && next_match); + + if (*next_match) + li = (*next_match)->next; + else + li = list->next; + + /* Initialize the return value */ + *next_match = NULL; + + for ( ; li != list; li = li->next) { + int cmp; + struct { + struct fd_list chain; + struct match_data md; + } * next_item = (void *)li; + + /* Check if the string matches this next item */ + CHECK_FCT( compare_match(str, len, &next_item->md, &cmp) ); + + if (cmp == 0) { + /* matched! */ + *next_match = li; + return 0; + } + + if (cmp < 0) /* we can stop searching */ + break; + } + + /* We're done with the list */ + return 0; +} + +static struct dict_object * AVP_MODELS[RTD_CRI_MAX]; + +/*********************************************************************/ + +/* Prepare the module */ int rtd_init(void) { + int i; + TRACE_ENTRY(); + for (i = 0; i < RTD_TAR_MAX; i++) { + fd_list_init(&TARGETS[i], NULL); + } + + for (i = 1; i < RTD_CRI_MAX; i++) { + switch (i) { + case RTD_CRI_OH: + CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &AVP_MODELS[i], ENOENT )); + break; + case RTD_CRI_OR: + CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &AVP_MODELS[i], ENOENT )); + break; + case RTD_CRI_DH: + CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Host", &AVP_MODELS[i], ENOENT )); + break; + case RTD_CRI_DR: + CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Realm", &AVP_MODELS[i], ENOENT )); + break; + case RTD_CRI_UN: + CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "User-Name", &AVP_MODELS[i], ENOENT )); + break; + case RTD_CRI_SI: + CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &AVP_MODELS[i], ENOENT )); + break; + default: + TRACE_DEBUG(INFO, "Missing definition in extension initializer"); + ASSERT( 0 ); + return EINVAL; + } + } + return 0; } +/* Destroy the module's data */ void rtd_fini(void) { + int i; + TRACE_ENTRY(); + for (i = 0; i < RTD_TAR_MAX; i++) { + while (!FD_IS_LIST_EMPTY(&TARGETS[i])) { + del_target((struct target *) TARGETS[i].next); + } + } + } +/* Add a new rule in the repository. this is called when the configuration file is being parsed */ int rtd_add(enum rtd_crit_type ct, char * criteria, enum rtd_targ_type tt, char * target, int score, int flags) { + struct fd_list * target_suiv = NULL; + struct fd_list * rule_suiv = NULL; + struct target * trg = NULL; + struct rule * rul = NULL; + TRACE_ENTRY("%d %p %d %p %d %x", ct, criteria, tt, target, score, flags); - CHECK_PARAMS((ct < RTD_CRI_MAX) && ((ct == 0) || criteria) && (tt < RTD_TAR_MAX) && target); + /* First, search in the TARGET list if we already have this target */ + for (target_suiv = TARGETS[tt].next; target_suiv != &TARGETS[tt]; target_suiv = target_suiv->next) { + int cmp; + struct target * cur = (struct target *)target_suiv; + + if (flags & RTD_TARG_REG) { + /* We are adding a regexp, it is saved in the list before the plain expressions */ + if (cur->md.is_regex == 0) + break; + } else { + /* We are adding a plain expression, save it after all regexps */ + if (cur->md.is_regex != 0) + continue; + } + + /* At this point, the type is the same, so compare the plain string value */ + cmp = strcmp(cur->md.plain, target); + if (cmp < 0) + continue; + + if (cmp == 0) /* We already have a target with the same string */ + trg = cur; + + break; + } + if (trg) { + /* Ok, we can free the target string, we will use the previously allocated one */ + free(target); + } else { + CHECK_MALLOC( trg = new_target(target, flags & RTD_TARG_REG) ); + fd_list_insert_before( target_suiv, &trg->chain ); + } + + /* Now, search for the rule position in this target's list */ + if (ct == 0) { + /* Special case: we don't have a criteria -- always create a rule element */ + CHECK_MALLOC( rul = new_rule(NULL, 0, score) ); + fd_list_insert_before( &trg->rules[0], &rul->chain ); + } else { + for (rule_suiv = trg->rules[ct].next; rule_suiv != &trg->rules[ct]; rule_suiv = rule_suiv->next) { + int cmp; + struct rule * cur = (struct rule *)rule_suiv; + + if (flags & RTD_CRIT_REG) { + /* We are adding a regexp, it is saved in the list before the plain expressions */ + if (cur->md.is_regex == 0) + break; + } else { + /* We are adding a plain expression, save it after all regexps */ + if (cur->md.is_regex != 0) + continue; + } + + /* At this point, the type is the same, so compare the plain string value */ + cmp = strcmp(cur->md.plain, criteria); + if (cmp < 0) + continue; + + if (cmp == 0) /* We already have a target with the same string */ + rul = cur; + + break; + } + + if (rul) { + /* Ok, we can free the target string, we will use the previously allocated one */ + free(criteria); + TRACE_DEBUG(INFO, "Warning: duplicate rule (%s : %s) found, merging score...", rul->md.plain, trg->md.plain); + rul->score += score; + } else { + CHECK_MALLOC( rul = new_rule(criteria, flags & RTD_CRIT_REG, score) ); + fd_list_insert_before( rule_suiv, &rul->chain ); + } + } return 0; } +/* Check if a message and list of eligible candidate match any of our rules, and update its score according to it. */ int rtd_process( struct msg * msg, struct fd_list * candidates ) { - return ENOTSUP; + struct fd_list * li; + struct { + enum { NOT_RESOLVED_YET = 0, NOT_FOUND, FOUND } status; + union avp_value * avp; + } parsed_msg_avp[RTD_CRI_MAX]; + + TRACE_ENTRY("%p %p", msg, candidates); + CHECK_PARAMS(msg && candidates); + + /* We delay looking for the AVPs in the message until we really need them. Another approach would be to parse the message once and save all needed AVPs. */ + memset(parsed_msg_avp, 0, sizeof(parsed_msg_avp)); + + /* For each candidate in the list */ + for (li = candidates->next; li != candidates; li = li->next) { + struct rtd_candidate * cand = (struct rtd_candidate *)li; + int i; + struct { + char * str; + size_t len; + } cand_data[RTD_TAR_MAX] = { + { cand->diamid, strlen(cand->diamid) }, + { cand->realm, strlen(cand->realm) } + }; + + for (i = 0; i < RTD_TAR_MAX; i++) { + /* Search the next rule matching this candidate in the i-th target list */ + struct target * target = NULL; + + do { + int j; + struct fd_list * l; + struct rule * r; + + CHECK_FCT ( get_next_match( &TARGETS[i], cand_data[i].str, cand_data[i].len, (void *)&target) ); + if (!target) + break; + + /* First, apply all rules of criteria RTD_CRI_ALL */ + for ( l = target->rules[0].next; l != &target->rules[0]; l = l->next ) { + r = (struct rule *)l; + cand->score += r->score; + TRACE_DEBUG(ANNOYING, "Applied rule {'%s' : '%s' += %d} to candidate '%s'", r->md.plain, target->md.plain, r->score, cand->diamid); + } + + /* The target is matching this candidate, check if there are additional rules criteria matching this message. */ + for ( j = 1; j < RTD_CRI_MAX; j++ ) { + if ( ! FD_IS_LIST_EMPTY(&target->rules[j]) ) { + /* if needed, find the required data in the message */ + if (parsed_msg_avp[j].status == NOT_RESOLVED_YET) { + struct avp * avp = NULL; + /* Search for the AVP in the message */ + CHECK_FCT( fd_msg_search_avp ( msg, AVP_MODELS[j], &avp ) ); + if (avp == NULL) { + parsed_msg_avp[j].status = NOT_FOUND; + } else { + struct avp_hdr * ahdr = NULL; + CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) ); + if (ahdr->avp_value == NULL) { + /* This should not happen, but anyway let's just ignore it */ + parsed_msg_avp[j].status = NOT_FOUND; + } else { + /* OK, we got the AVP */ + parsed_msg_avp[j].status = FOUND; + parsed_msg_avp[j].avp = ahdr->avp_value; + } + } + } + + /* If we did not find the data for these rules in the message, just skip the series */ + if (parsed_msg_avp[j].status == NOT_FOUND) { + TRACE_DEBUG(ANNOYING, "Skipping series of rules %d of target '%s', criteria absent from the message", j, target->md.plain); + continue; + } + + /* OK, we can now check if one of our rule's criteria match the message content */ + r = NULL; + do { + CHECK_FCT ( get_next_match( &target->rules[j], parsed_msg_avp[j].avp->os.data, parsed_msg_avp[j].avp->os.len, (void *)&r) ); + if (!r) + break; + + cand->score += r->score; + TRACE_DEBUG(ANNOYING, "Applied rule {'%s' : '%s' += %d} to candidate '%s'", r->md.plain, target->md.plain, r->score, cand->diamid); + } while (1); + } + } + } while (1); + } + } + + return 0; } void rtd_dump(void) { + int i; fd_log_debug("[rt_default] Dumping rules repository...\n"); + for (i = 0; i < RTD_TAR_MAX; i++) { + if (!FD_IS_LIST_EMPTY( &TARGETS[i] )) { + struct fd_list * li; + fd_log_debug(" Targets list %d:\n", i); + for (li = TARGETS[i].next; li != &TARGETS[i]; li = li->next) { + dump_target(4, (struct target *)li); + } + } + } + fd_log_debug("[rt_default] End of dump\n"); }
--- a/freeDiameter/routing_dispatch.c Fri Jan 29 18:57:40 2010 +0900 +++ b/freeDiameter/routing_dispatch.c Tue Feb 02 10:15:05 2010 +0900 @@ -844,7 +844,7 @@ CHECK_FCT( pthread_rwlock_rdlock(&fd_g_activ_peers_rw) ); for (li = fd_g_activ_peers.next; li != &fd_g_activ_peers; li = li->next) { struct fd_peer * p = (struct fd_peer *)li->o; - CHECK_FCT_DO( ret = fd_rtd_candidate_add(rtd, p->p_hdr.info.pi_diamid), { CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_activ_peers_rw), ); return ret; } ); + CHECK_FCT_DO( ret = fd_rtd_candidate_add(rtd, p->p_hdr.info.pi_diamid, p->p_hdr.info.runtime.pir_realm), { CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_activ_peers_rw), ); return ret; } ); } CHECK_FCT( pthread_rwlock_unlock(&fd_g_activ_peers_rw) );
--- a/include/freeDiameter/CMakeLists.txt Fri Jan 29 18:57:40 2010 +0900 +++ b/include/freeDiameter/CMakeLists.txt Tue Feb 02 10:15:05 2010 +0900 @@ -64,7 +64,8 @@ ENDIF(NOT HAVE_NATIVE_SCTP) # Now check the number of args of this function, since it changed between Ubuntu 9.04 and 9.10 SET(CHECK_SCTP_CONNECTX_4_ARGS_SOURCE_CODE " - #include <netinet/sctp.h>; + #include <unistd.h> + #include <netinet/sctp.h> int main() { return sctp_connectx(0, NULL, 0, NULL); }
--- a/include/freeDiameter/libfreeDiameter.h Fri Jan 29 18:57:40 2010 +0900 +++ b/include/freeDiameter/libfreeDiameter.h Tue Feb 02 10:15:05 2010 +0900 @@ -1631,7 +1631,7 @@ /*============================================================*/ /* The following functions are helpers for the routing module. - The routing data is stored in the message it-self. */ + The routing data is stored in the message itself. */ /* Structure that contains the routing data for a message */ struct rt_data; @@ -1641,7 +1641,7 @@ void fd_rtd_free(struct rt_data ** rtd); /* Add a peer to the candidates list */ -int fd_rtd_candidate_add(struct rt_data * rtd, char * peerid); +int fd_rtd_candidate_add(struct rt_data * rtd, char * peerid, char * realm); /* Remove a peer from the candidates (if it is found) */ void fd_rtd_candidate_del(struct rt_data * rtd, char * peerid, size_t sz /* if !0, peerid does not need to be \0 terminated */); @@ -1656,6 +1656,7 @@ struct rtd_candidate { struct fd_list chain; /* link in the list returned by the previous fct */ char * diamid; /* the diameter Id of the peer */ + char * realm; /* the diameter realm of the peer (if known) */ int score; /* the current routing score for this peer, see fd_rt_out_register definition for details */ };
--- a/libfreeDiameter/rt_data.c Fri Jan 29 18:57:40 2010 +0900 +++ b/libfreeDiameter/rt_data.c Tue Feb 02 10:15:05 2010 +0900 @@ -88,6 +88,7 @@ fd_list_unlink(&c->chain); free(c->diamid); + free(c->realm); free(c); } @@ -106,7 +107,7 @@ } /* Add a peer to the candidates list */ -int fd_rtd_candidate_add(struct rt_data * rtd, char * peerid) +int fd_rtd_candidate_add(struct rt_data * rtd, char * peerid, char * realm) { struct fd_list * prev; struct rtd_candidate * new; @@ -129,6 +130,7 @@ memset(new, 0, sizeof(struct rtd_candidate) ); fd_list_init(&new->chain, NULL); CHECK_MALLOC( new->diamid = strdup(peerid) ); + CHECK_MALLOC( new->realm = strdup(realm) ); fd_list_insert_after(prev, &new->chain); @@ -164,6 +166,7 @@ /* Found it! Remove it */ fd_list_unlink(&c->chain); free(c->diamid); + free(c->realm); free(c); break; }