Navigation


Changeset 168:6db078b955e3 in freeDiameter for extensions/rt_default


Ignore:
Timestamp:
Feb 2, 2010, 10:15:05 AM (14 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Completed rt_default extension

Location:
extensions/rt_default
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • extensions/rt_default/CMakeLists.txt

    r167 r168  
    11# The rt_default extension
    22PROJECT("Configurable routing extension" C)
     3
     4# Check if REG_STARTEND is provided on the host
     5SET(CHECK_REG_STARTEND_SOURCE_CODE "
     6        #include <unistd.h>
     7        #include <regex.h>
     8        int main() {
     9           return regexec(NULL, NULL, 0, NULL, REG_STARTEND);
     10        }
     11        ")
     12CHECK_C_SOURCE_COMPILES("${CHECK_REG_STARTEND_SOURCE_CODE}" HAVE_REG_STARTEND)
     13# Generate the host.h file
     14CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/rt_default-host.h.in ${CMAKE_CURRENT_BINARY_DIR}/rt_default-host.h)
    315
    416# Parser files
     
    1729)
    1830
     31INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
     32
    1933# Compile these files as a freeDiameter extension
    2034FD_ADD_EXTENSION(rt_default ${RT_DEFAULT_SRC})
  • extensions/rt_default/rt_default.c

    r167 r168  
    6969        CHECK_FCT( rtd_conf_handle(conffile) );
    7070       
    71 #if 1
     71#if 0
    7272        /* Dump the rules */
    7373        rtd_dump();
  • extensions/rt_default/rt_default.h

    r167 r168  
    3939 */
    4040 
     41/* FreeDiameter's common include file */
    4142#include <freeDiameter/extension.h>
     43
     44/* Host configuration for this specific extension */
     45#include <rt_default-host.h>
    4246
    4347/* Parse the configuration file */
  • extensions/rt_default/rtd_conf.l

    r167 r168  
    133133(?i:"un")               {       return UN;      }
    134134(?i:"si")               {       return SI;      }
    135 (?i:"i")                {       return IDENTITY;}
    136 (?i:"r")                {       return REALM;   }
     135(?i:"rlm")              {       return REALM;   }
    137136                       
    138137        /* Valid single characters for yyparse */
  • extensions/rt_default/rtd_conf.y

    r167 r168  
    152152%token          SI
    153153
    154 %token          IDENTITY
    155154%token          REALM
    156155
     
    180179                                                YYERROR;
    181180                                        } );
     181                               
     182                                rules_added++;
    182183                        }
    183184                        ;
     
    242243
    243244        /* Details of the TARGET type */
    244 TARGET:                 IDENTITY '=' TSTRING
    245                         {
    246                                 $$.str = $3.str;
    247                                 $$.regex =$3.regex;
     245TARGET:                 TSTRING
     246                        {
     247                                $$.str = $1.str;
     248                                $$.regex =$1.regex;
    248249                                $$.type = RTD_TAR_ID;
    249250                        }
  • extensions/rt_default/rtd_rules.c

    r167 r168  
    5050 */
    5151
    52 /* 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. */
     52/* Structure to hold the data that is used for matching. */
    5353struct match_data {
    5454        int      is_regex;      /* determines how the string is matched */
     
    5757};
    5858
     59/* The sentinels for the TARGET lists */
     60static struct fd_list   TARGETS[RTD_TAR_MAX];
     61
    5962/* Structure of a TARGET element */
    6063struct target {
    61         struct fd_list          chain;  /* link in the top-level list */
    62         struct match_data       md;     /* the data to determine if the current candidate matches this element */
    63         struct fd_list          rules;  /* Sentinel for the list of rules applying to this target */
     64        struct fd_list          chain;                  /* link in the top-level list */
     65        struct match_data       md;                     /* the data to determine if the current candidate matches this element */
     66        struct fd_list          rules[RTD_CRI_MAX];     /* Sentinels for the lists of rules applying to this target. One list per rtd_crit_type */
    6467        /* 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 */
    6568};
     
    6871struct rule {
    6972        struct fd_list          chain;  /* link in the parent target list */
    70         enum rtd_crit_type      type;   /* What kind of criteria the message must match for the rule to apply */
    71         struct match_data       md;     /* the data that the criteria must match, if it is different from RTD_CRI_ALL */
     73        struct match_data       md;     /* the data that the criteria must match, -- ignored for RTD_CRI_ALL */
    7274        int                     score;  /* The score added to the candidate, if the message matches this criteria */
     75        /* The type of rule depends on the sentinel */
    7376};
    7477
    75 /* The sentinels for the TARGET lists */
    76 static struct fd_list   TARGETS[RTD_TAR_MAX];
    77 
    78 
    79 
     78/*********************************************************************/
     79
     80/* Compile a regular expression pattern */
     81static int compile_regex( regex_t  * preg, char * str )
     82{
     83        int err;
     84       
     85        /* Compile the regular expression */
     86        err = regcomp(preg, str, REG_EXTENDED | REG_NOSUB);
     87        if (err != 0) {
     88                char * buf;
     89                size_t bl;
     90               
     91                /* Error while compiling the regex */
     92                TRACE_DEBUG(INFO, "Error while compiling the regular expression '%s':", str);
     93               
     94                /* Get the error message size */
     95                bl = regerror(err, preg, NULL, 0);
     96               
     97                /* Alloc the buffer for error message */
     98                CHECK_MALLOC( buf = malloc(bl) );
     99               
     100                /* Get the error message content */
     101                regerror(err, preg, buf, bl);
     102                TRACE_DEBUG(INFO, "\t%s", buf);
     103               
     104                /* Free the buffer, return the error */
     105                free(buf);
     106                return EINVAL;
     107        }
     108
     109        return 0;
     110}
     111
     112/* Create a target item and initialize its content */
     113static struct target * new_target(char * str, int regex)
     114{
     115        int i;
     116        struct target *new = NULL;
     117        CHECK_MALLOC_DO( new = malloc(sizeof(struct target)), return NULL );
     118        memset(new, 0, sizeof(struct target));
     119       
     120        fd_list_init(&new->chain, new);
     121        new->md.plain = str;
     122        new->md.is_regex = regex;
     123        if (regex) {
     124                CHECK_FCT_DO( compile_regex(&new->md.preg, str),
     125                        {
     126                                free(new);
     127                                return NULL;
     128                        } );
     129        }
     130        for (i = 0; i < RTD_CRI_MAX; i++) {
     131                fd_list_init(&new->rules[i], new);
     132        }
     133        return new;
     134}
     135
     136/* Create a rule item and initialize its content; return NULL in case of error */
     137static struct rule * new_rule(char * str, int regex, int score)
     138{
     139        struct rule *new = NULL;
     140        CHECK_MALLOC_DO( new = malloc(sizeof(struct rule)), return NULL );
     141        memset(new, 0, sizeof(struct rule));
     142       
     143        fd_list_init(&new->chain, new);
     144        new->md.plain = str;
     145        new->md.is_regex = regex;
     146        if (regex) {
     147                CHECK_FCT_DO( compile_regex(&new->md.preg, str),
     148                        {
     149                                free(new);
     150                                return NULL;
     151                        } );
     152        }
     153        new->score = score;
     154        return new;
     155}
     156
     157/* Debug functions */
     158static void dump_rule(int indent, struct rule * rule)
     159{
     160        fd_log_debug("%*s%s%s%s += %d\n",
     161                indent, "",
     162                rule->md.is_regex ? "[" : "'",
     163                rule->md.plain,
     164                rule->md.is_regex ? "]" : "'",
     165                rule->score);
     166}
     167static void dump_target(int indent, struct target * target)
     168{
     169        int i;
     170        fd_log_debug("%*s%s%s%s :\n",
     171                indent, "",
     172                target->md.is_regex ? "[" : "'",
     173                target->md.plain ?: "(empty)",
     174                target->md.is_regex ? "]" : "'");
     175        for (i = 0; i < RTD_CRI_MAX; i++) {
     176                if (! FD_IS_LIST_EMPTY(&target->rules[i])) {
     177                        struct fd_list * li;
     178                        fd_log_debug("%*s  rules[%d]:\n",
     179                                indent, "", i);
     180                        for (li = target->rules[i].next; li != &target->rules[i]; li = li->next) {
     181                                dump_rule(indent + 3, (struct rule *)li);
     182                        }
     183                }
     184        }
     185}
     186
     187static void clear_md(struct match_data * md)
     188{
     189        /* delete the string */
     190        if (md->plain) {
     191                free(md->plain);
     192                md->plain = NULL;
     193        }
     194       
     195        /* delete the preg if needed */
     196        if (md->is_regex) {
     197                regfree(&md->preg);
     198                md->is_regex = 0;
     199        }
     200}
     201
     202/* Destroy a rule item */
     203static void del_rule(struct rule * del)
     204{
     205        /* Unlink this rule */
     206        fd_list_unlink(&del->chain);
     207       
     208        /* Delete the match data */
     209        clear_md(&del->md);
     210       
     211        free(del);
     212}
     213
     214/* Destroy a target item, and all its rules */
     215static void del_target(struct target * del)
     216{
     217        int i;
     218       
     219        /* Unlink this target */
     220        fd_list_unlink(&del->chain);
     221       
     222        /* Delete the match data */
     223        clear_md(&del->md);
     224       
     225        /* Delete the children rules */
     226        for (i = 0; i < RTD_CRI_MAX; i++) {
     227                while (! FD_IS_LIST_EMPTY(&del->rules[i]) ) {
     228                        del_rule((struct rule *)(del->rules[i].next));
     229                }
     230        }
     231       
     232        free(del);
     233}
     234
     235
     236/* Compare a string with a match_data value. *res contains the result of the comparison (always >0 for regex non-match situations) */
     237static int compare_match(char * str, size_t len, struct match_data * md, int * res)
     238{
     239        int err;
     240       
     241        CHECK_PARAMS( str && md && res );
     242       
     243        /* Plain strings: we compare with strncasecmp */
     244        if (md->is_regex == 0) {
     245                *res = strncasecmp(str, md->plain, len);
     246                return 0;
     247        }
     248
     249        /* Regexp */
     250        *res = 1;
     251       
     252#ifdef HAVE_REG_STARTEND
     253        {
     254                regmatch_t pmatch[1];
     255                memset(pmatch, 0, sizeof(pmatch));
     256                pmatch[0].rm_so = 0;
     257                pmatch[0].rm_eo = len;
     258                err = regexec(&md->preg, str, 0, pmatch, REG_STARTEND);
     259        }
     260#else /* HAVE_REG_STARTEND */
     261        {
     262                /* We have to create a copy of the string in this case */
     263                char *mystrcpy;
     264                CHECK_MALLOC( mystrcpy = malloc(len + 1) );
     265                memcpy(mystrcpy, str, len);
     266                mystrcpy[len] = '\0';
     267                err = regexec(&md->preg, mystrcpy, 0, NULL, 0);
     268                free(mystrcpy);
     269        }
     270#endif /* HAVE_REG_STARTEND */
     271       
     272        /* Now check the result */
     273        if (err == 0) {
     274                /* We have a match */
     275                *res = 0;
     276                return 0;
     277        }
     278       
     279        if (err == REG_NOMATCH) {
     280                *res = 1;
     281                return 0;
     282        }
     283       
     284        /* In other cases, we have an error */
     285        {
     286                char * buf;
     287                size_t bl;
     288               
     289                /* Error while compiling the regex */
     290                TRACE_DEBUG(INFO, "Error while executing the regular expression '%s':", md->plain);
     291               
     292                /* Get the error message size */
     293                bl = regerror(err, &md->preg, NULL, 0);
     294               
     295                /* Alloc the buffer for error message */
     296                CHECK_MALLOC( buf = malloc(bl) );
     297               
     298                /* Get the error message content */
     299                regerror(err, &md->preg, buf, bl);
     300                TRACE_DEBUG(INFO, "\t%s", buf);
     301               
     302                /* Free the buffer, return the error */
     303                free(buf);
     304        }
     305
     306        return (err == REG_ESPACE) ? ENOMEM : EINVAL;
     307}
     308
     309/* 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. */
     310static int get_next_match(struct fd_list * list, char * str, size_t len, struct fd_list ** next_match)
     311{
     312        struct fd_list * li;
     313       
     314        TRACE_ENTRY("%p %p %zd %p", list, str, len, next_match);
     315        CHECK_PARAMS(list && str && len && next_match);
     316       
     317        if (*next_match)
     318                li = (*next_match)->next;
     319        else
     320                li = list->next;
     321       
     322        /* Initialize the return value */
     323        *next_match = NULL;
     324       
     325        for ( ; li != list; li = li->next) {
     326                int cmp;
     327                struct {
     328                        struct fd_list          chain;
     329                        struct match_data       md;
     330                } * next_item = (void *)li;
     331               
     332                /* Check if the string matches this next item */
     333                CHECK_FCT( compare_match(str, len, &next_item->md, &cmp) );
     334               
     335                if (cmp == 0) {
     336                        /* matched! */
     337                        *next_match = li;
     338                        return 0;
     339                }
     340               
     341                if (cmp < 0) /* we can stop searching */
     342                        break;
     343        }
     344       
     345        /* We're done with the list */
     346        return 0;
     347}
     348
     349static struct dict_object * AVP_MODELS[RTD_CRI_MAX];
     350
     351/*********************************************************************/
     352
     353/* Prepare the module */
    80354int rtd_init(void)
    81355{
     356        int i;
     357       
    82358        TRACE_ENTRY();
    83359       
     360        for (i = 0; i < RTD_TAR_MAX; i++) {
     361                fd_list_init(&TARGETS[i], NULL);
     362        }
     363       
     364        for (i = 1; i < RTD_CRI_MAX; i++) {
     365                switch (i) {
     366                        case RTD_CRI_OH:
     367                                CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &AVP_MODELS[i], ENOENT ));
     368                                break;
     369                        case RTD_CRI_OR:
     370                                CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &AVP_MODELS[i], ENOENT ));
     371                                break;
     372                        case RTD_CRI_DH:
     373                                CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Host", &AVP_MODELS[i], ENOENT ));
     374                                break;
     375                        case RTD_CRI_DR:
     376                                CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Realm", &AVP_MODELS[i], ENOENT ));
     377                                break;
     378                        case RTD_CRI_UN:
     379                                CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "User-Name", &AVP_MODELS[i], ENOENT ));
     380                                break;
     381                        case RTD_CRI_SI:
     382                                CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &AVP_MODELS[i], ENOENT ));
     383                                break;
     384                        default:
     385                                TRACE_DEBUG(INFO, "Missing definition in extension initializer");
     386                                ASSERT( 0 );
     387                                return EINVAL;
     388                }
     389        }
     390       
    84391        return 0;
    85392}
    86393
     394/* Destroy the module's data */
    87395void rtd_fini(void)
    88396{
     397        int i;
     398       
    89399        TRACE_ENTRY();
    90400
    91 }
    92 
     401        for (i = 0; i < RTD_TAR_MAX; i++) {
     402                while (!FD_IS_LIST_EMPTY(&TARGETS[i])) {
     403                        del_target((struct target *) TARGETS[i].next);
     404                }
     405        }
     406       
     407}
     408
     409/* Add a new rule in the repository. this is called when the configuration file is being parsed */
    93410int rtd_add(enum rtd_crit_type ct, char * criteria, enum rtd_targ_type tt, char * target, int score, int flags)
    94411{
     412        struct fd_list * target_suiv = NULL;
     413        struct fd_list * rule_suiv = NULL;
     414        struct target * trg = NULL;
     415        struct rule * rul = NULL;
     416       
    95417        TRACE_ENTRY("%d %p %d %p %d %x", ct, criteria, tt, target, score, flags);
    96        
    97418        CHECK_PARAMS((ct < RTD_CRI_MAX) && ((ct == 0) || criteria) && (tt < RTD_TAR_MAX) && target);
    98419       
    99        
     420        /* First, search in the TARGET list if we already have this target */
     421        for (target_suiv = TARGETS[tt].next; target_suiv != &TARGETS[tt]; target_suiv = target_suiv->next) {
     422                int cmp;
     423                struct target * cur = (struct target *)target_suiv;
     424               
     425                if (flags & RTD_TARG_REG) {
     426                        /* We are adding a regexp, it is saved in the list before the plain expressions */
     427                        if (cur->md.is_regex == 0)
     428                                break; 
     429                } else {
     430                        /* We are adding a plain expression, save it after all regexps */
     431                        if (cur->md.is_regex != 0)
     432                                continue;
     433                }
     434               
     435                /* At this point, the type is the same, so compare the plain string value */
     436                cmp = strcmp(cur->md.plain, target);
     437                if (cmp < 0)
     438                        continue;
     439               
     440                if (cmp == 0) /* We already have a target with the same string */
     441                        trg = cur;
     442               
     443                break;
     444        }
     445       
     446        if (trg) {
     447                /* Ok, we can free the target string, we will use the previously allocated one */
     448                free(target);
     449        } else {
     450                CHECK_MALLOC( trg = new_target(target, flags & RTD_TARG_REG) );
     451                fd_list_insert_before( target_suiv, &trg->chain );
     452        }
     453       
     454        /* Now, search for the rule position in this target's list */
     455        if (ct == 0) {
     456                /* Special case: we don't have a criteria -- always create a rule element */
     457                CHECK_MALLOC( rul = new_rule(NULL, 0, score) );
     458                fd_list_insert_before( &trg->rules[0], &rul->chain );
     459        } else {
     460                for (rule_suiv = trg->rules[ct].next; rule_suiv != &trg->rules[ct]; rule_suiv = rule_suiv->next) {
     461                        int cmp;
     462                        struct rule * cur = (struct rule *)rule_suiv;
     463
     464                        if (flags & RTD_CRIT_REG) {
     465                                /* We are adding a regexp, it is saved in the list before the plain expressions */
     466                                if (cur->md.is_regex == 0)
     467                                        break; 
     468                        } else {
     469                                /* We are adding a plain expression, save it after all regexps */
     470                                if (cur->md.is_regex != 0)
     471                                        continue;
     472                        }
     473
     474                        /* At this point, the type is the same, so compare the plain string value */
     475                        cmp = strcmp(cur->md.plain, criteria);
     476                        if (cmp < 0)
     477                                continue;
     478
     479                        if (cmp == 0) /* We already have a target with the same string */
     480                                rul = cur;
     481
     482                        break;
     483                }
     484       
     485                if (rul) {
     486                        /* Ok, we can free the target string, we will use the previously allocated one */
     487                        free(criteria);
     488                        TRACE_DEBUG(INFO, "Warning: duplicate rule (%s : %s) found, merging score...", rul->md.plain, trg->md.plain);
     489                        rul->score += score;
     490                } else {
     491                        CHECK_MALLOC( rul = new_rule(criteria, flags & RTD_CRIT_REG, score) );
     492                        fd_list_insert_before( rule_suiv, &rul->chain );
     493                }
     494        }
    100495       
    101496        return 0;
    102497}
    103498
     499/* Check if a message and list of eligible candidate match any of our rules, and update its score according to it. */
    104500int rtd_process( struct msg * msg, struct fd_list * candidates )
    105501{
    106         return ENOTSUP;
     502        struct fd_list * li;
     503        struct {
     504                enum { NOT_RESOLVED_YET = 0, NOT_FOUND, FOUND } status;
     505                union avp_value * avp;
     506        } parsed_msg_avp[RTD_CRI_MAX];
     507       
     508        TRACE_ENTRY("%p %p", msg, candidates);
     509        CHECK_PARAMS(msg && candidates);
     510       
     511        /* 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. */
     512        memset(parsed_msg_avp, 0, sizeof(parsed_msg_avp));
     513       
     514        /* For each candidate in the list */
     515        for (li = candidates->next; li != candidates; li = li->next) {
     516                struct rtd_candidate * cand = (struct rtd_candidate *)li;
     517                int i;
     518                struct {
     519                        char * str;
     520                        size_t len;
     521                } cand_data[RTD_TAR_MAX] = {
     522                        { cand->diamid,  strlen(cand->diamid) },
     523                        { cand->realm,   strlen(cand->realm)  }
     524                };
     525               
     526                for (i = 0; i < RTD_TAR_MAX; i++) {
     527                        /* Search the next rule matching this candidate in the i-th target list */
     528                        struct target * target = NULL;
     529                       
     530                        do {
     531                                int j;
     532                                struct fd_list * l;
     533                                struct rule * r;
     534                               
     535                                CHECK_FCT ( get_next_match( &TARGETS[i], cand_data[i].str, cand_data[i].len, (void *)&target) );
     536                                if (!target)
     537                                        break;
     538                               
     539                                /* First, apply all rules of criteria RTD_CRI_ALL */
     540                                for ( l = target->rules[0].next; l != &target->rules[0]; l = l->next ) {
     541                                        r = (struct rule *)l;
     542                                        cand->score += r->score;
     543                                        TRACE_DEBUG(ANNOYING, "Applied rule {'%s' : '%s' += %d} to candidate '%s'", r->md.plain, target->md.plain, r->score, cand->diamid);
     544                                }
     545                               
     546                                /* The target is matching this candidate, check if there are additional rules criteria matching this message. */
     547                                for ( j = 1; j < RTD_CRI_MAX; j++ ) {
     548                                        if ( ! FD_IS_LIST_EMPTY(&target->rules[j]) ) {
     549                                                /* if needed, find the required data in the message */
     550                                                if (parsed_msg_avp[j].status == NOT_RESOLVED_YET) {
     551                                                        struct avp * avp = NULL;
     552                                                        /* Search for the AVP in the message */
     553                                                        CHECK_FCT( fd_msg_search_avp ( msg, AVP_MODELS[j], &avp ) );
     554                                                        if (avp == NULL) {
     555                                                                parsed_msg_avp[j].status = NOT_FOUND;
     556                                                        } else {
     557                                                                struct avp_hdr * ahdr = NULL;
     558                                                                CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
     559                                                                if (ahdr->avp_value == NULL) {
     560                                                                        /* This should not happen, but anyway let's just ignore it */
     561                                                                        parsed_msg_avp[j].status = NOT_FOUND;
     562                                                                } else {
     563                                                                        /* OK, we got the AVP */
     564                                                                        parsed_msg_avp[j].status = FOUND;
     565                                                                        parsed_msg_avp[j].avp = ahdr->avp_value;
     566                                                                }
     567                                                        }
     568                                                }
     569                                               
     570                                                /* If we did not find the data for these rules in the message, just skip the series */
     571                                                if (parsed_msg_avp[j].status == NOT_FOUND) {
     572                                                        TRACE_DEBUG(ANNOYING, "Skipping series of rules %d of target '%s', criteria absent from the message", j, target->md.plain);
     573                                                        continue;
     574                                                }
     575                                               
     576                                                /* OK, we can now check if one of our rule's criteria match the message content */
     577                                                r = NULL;
     578                                                do {
     579                                                        CHECK_FCT ( get_next_match( &target->rules[j], parsed_msg_avp[j].avp->os.data, parsed_msg_avp[j].avp->os.len, (void *)&r) );
     580                                                        if (!r)
     581                                                                break;
     582                                                       
     583                                                        cand->score += r->score;
     584                                                        TRACE_DEBUG(ANNOYING, "Applied rule {'%s' : '%s' += %d} to candidate '%s'", r->md.plain, target->md.plain, r->score, cand->diamid);
     585                                                } while (1);
     586                                        }
     587                                }
     588                        } while (1);
     589                }
     590        }
     591       
     592        return 0;
    107593}
    108594
    109595void rtd_dump(void)
    110596{
     597        int i;
    111598        fd_log_debug("[rt_default] Dumping rules repository...\n");
     599        for (i = 0; i < RTD_TAR_MAX; i++) {
     600                if (!FD_IS_LIST_EMPTY( &TARGETS[i] )) {
     601                        struct fd_list * li;
     602                        fd_log_debug("  Targets list %d:\n", i);
     603                        for (li = TARGETS[i].next; li != &TARGETS[i]; li = li->next) {
     604                                dump_target(4, (struct target *)li);
     605                        }
     606                }
     607        }
     608       
    112609        fd_log_debug("[rt_default] End of dump\n");
    113610}
Note: See TracChangeset for help on using the changeset viewer.