Navigation


Changeset 544:a0e3af6f94fb in freeDiameter


Ignore:
Timestamp:
Sep 14, 2010, 4:04:59 PM (14 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Improve the RADIUS duplicates management. Default cache is set to 60 seconds.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • extensions/app_radgw/rgw_clients.c

    r539 r544  
    4141
    4242#define REVERSE_DNS_SIZE_MAX    512 /* length of our buffer for reverse DNS */
     43#define DUPLICATE_CHECK_LIFETIME 60 /* number of seconds that the received RADIUS records are kept for duplicate checking . TODO: make it configurable if needed */
    4344
    4445/* Ordered lists of clients. The order relationship is a memcmp on the address zone.
     
    4950static struct fd_list cli_ip6 = FD_LIST_INITIALIZER(cli_ip6);
    5051
    51 /* Mutex to protect the previous lists */
    52 static pthread_mutex_t cli_mtx = PTHREAD_MUTEX_INITIALIZER;
     52/* Lock to protect the previous lists. We use a rwlock because this list is mostly static, to allow parallel reading */
     53static pthread_rwlock_t cli_rwl = PTHREAD_RWLOCK_INITIALIZER;
     54
     55/* Structure describing one received RADIUS message, for duplicate checks purpose. */
     56struct req_info {
     57        uint16_t        port;   /* UDP source port of the request */
     58        uint8_t         id;     /* The identifier in the request header */
     59        uint8_t         auth[16]; /* Request authenticator, since some RADIUS clients do not implement the id mechanism properly. */
     60        struct radius_msg *ans; /* The replied answer if any, in case the previous answer got lost. */
     61       
     62        int             nbdup;  /* Number of times this request was received as a duplicate */
     63        struct fd_list  by_id;    /* The list of requests ordered by their id, port, and auth */
     64        time_t          received; /* When was the last duplicate received? */
     65        struct fd_list  by_time;  /* The list of requests ordered by the 'received' value . */
     66};
     67
     68static pthread_t dbt_expire = (pthread_t)NULL; /* The thread that will remove old requests information from all clients (one thread for all) */
    5369
    5470/* Structure describing one client */
    5571struct rgw_client {
    56         /* Link information in global list */
     72        /* Link information in global list (cli_ip or cli_ip6) */
    5773        struct fd_list          chain;
    5874       
     
    8298        }                       key;
    8399       
    84         /* information of previous msg received, for duplicate checks -- we keep the last DUPLICATE_MESSAGES_BUFFER messages on each port. */
    85 #define DUPLICATE_MESSAGES_BUFFER 200 /* This should actually be replaced with a time-based dynamic list! TODO... */
     100        /* information of previous msg received, for duplicate checks. */
    86101        struct {
    87                 int     cnt;   /* Counts the number of (different) requests we received */
    88                 struct {
    89                         uint16_t        port;     /* The source UDP port of the request */
    90                         uint8_t         id;       /* The identifier in the request */
    91                         uint8_t         auth[16]; /* The request authenticator, because some NAS are not using identifier properly. */
    92                         struct radius_msg * ans;  /* When the answer has been sent already, keep it so we can send it back */
    93                         int             nbdup;    /* count the number of duplicate RADIUS requests we received on this message */
    94                 } msg_info[DUPLICATE_MESSAGES_BUFFER];
    95         } duplicates_info[2]; /*[0] for auth, [1] for acct. */
     102                pthread_mutex_t dupl_lock;    /* The mutex protecting the following lists */
     103                struct fd_list  dupl_by_id;   /* The list of req_info structures ordered by their id, port, and auth */
     104                struct fd_list  dupl_by_time; /* The list of req_info structures ordered by their time (approximative) */
     105        } dupl_info[2]; /*[0] for auth, [1] for acct. */
    96106};
    97107
    98108
    99 
    100 /* create a new rgw_client. the arguments are moved into the structure (to limit malloc & free calls). */
     109/* Create a new req_info structure and initialize its data from a RADIUS request message */
     110static struct req_info * dupl_new_req_info(struct rgw_radius_msg_meta *msg) {
     111        struct req_info * ret = NULL;
     112        CHECK_MALLOC_DO( ret = malloc(sizeof(struct req_info)), return NULL );
     113        memset(ret, 0, sizeof(struct req_info));
     114        ret->port = msg->port;
     115        ret->id   = msg->radius.hdr->identifier;
     116        memcpy(&ret->auth[0], &msg->radius.hdr->authenticator[0], 16);
     117        fd_list_init(&ret->by_id, ret);
     118        fd_list_init(&ret->by_time, ret);
     119        ret->received = time(NULL);
     120        return ret;
     121}
     122
     123/* Destroy a req_info structure, after it has been unlinked */
     124static void dupl_free_req_info(struct req_info * r) {
     125        CHECK_PARAMS_DO( r && FD_IS_LIST_EMPTY(&r->by_id) && FD_IS_LIST_EMPTY(&r->by_time), return );
     126        if (r->ans) {
     127                /* Free this RADIUS message */
     128                radius_msg_free(r->ans);
     129                free(r->ans);
     130        }
     131       
     132        /* Use r->nbdup for some purpose? */
     133       
     134        free(r);
     135}
     136
     137/* The core of the purge thread */
     138static int dupl_purge_list(struct fd_list * clients) {
     139        struct fd_list *li = NULL;
     140        for (li = clients->next; li != clients; li = li->next) {
     141                struct rgw_client * client = (struct rgw_client *)li;
     142                int p;
     143                for (p=0; p<=1; p++) {
     144                        /* Lock this list */
     145                        time_t now;
     146                        CHECK_POSIX( pthread_mutex_lock(&client->dupl_info[p].dupl_lock) );
     147                       
     148                        now = time(NULL);
     149                       
     150                        while (!FD_IS_LIST_EMPTY(&client->dupl_info[p].dupl_by_time)) {
     151                                /* Check the first item in the list */
     152                                struct req_info * r = (struct req_info *)(client->dupl_info[p].dupl_by_time.next->o);
     153                               
     154                                if (now - r->received > DUPLICATE_CHECK_LIFETIME) {
     155                                        /* Remove this record */
     156                                        fd_list_unlink(&r->by_time);
     157                                        fd_list_unlink(&r->by_id);
     158                                        dupl_free_req_info(r);
     159                                } else {
     160                                        /* We are done for this list */
     161                                        break;
     162                                }
     163                        }
     164                       
     165                        CHECK_POSIX( pthread_mutex_unlock(&client->dupl_info[p].dupl_lock) );
     166                }
     167        }
     168        return 0;
     169}
     170
     171/* Thread that purges old RADIUS requests */
     172static void * dupl_th(void * arg) {
     173        /* Set the thread name */
     174        fd_log_threadname ( "app_radgw:duplicate_purge" );
     175       
     176        /* The thread will be canceled */
     177        while (1) {
     178               
     179                /* We don't use a cond var, we simply wake up every 5 seconds. If the size of the duplicate cache is critical, it might be changed */
     180                sleep(5);
     181               
     182                /* When we wake up, we will check all clients duplicate lists one by one */
     183                CHECK_POSIX_DO( pthread_rwlock_rdlock(&cli_rwl), break );
     184               
     185                CHECK_FCT_DO( dupl_purge_list(&cli_ip), break );
     186                CHECK_FCT_DO( dupl_purge_list(&cli_ip6), break );
     187               
     188                CHECK_POSIX_DO( pthread_rwlock_unlock(&cli_rwl), break );
     189       
     190                /* Loop */
     191        }
     192       
     193        /* If we reach this part, some fatal error was encountered */
     194        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
     195        TRACE_DEBUG(FULL, "Thread terminated");
     196        return NULL;
     197}
     198
     199
     200/* create a new rgw_client. the arguments are MOVED into the structure (to limit malloc & free calls). */
    101201static int client_create(struct rgw_client ** res, struct sockaddr ** ip_port, unsigned char ** key, size_t keylen, enum rgw_cli_type type )
    102202{
    103203        struct rgw_client *tmp = NULL;
    104204        char buf[255];
    105         int ret;
     205        int ret, i;
    106206        int loc = 0;
    107207       
     
    126226        fd_list_init(&tmp->chain, NULL);
    127227       
     228        /* Initialize the duplicate list info */
     229        for (i=0; i<=1; i++) {
     230                CHECK_POSIX( pthread_mutex_init(&tmp->dupl_info[0].dupl_lock, NULL) );
     231                fd_list_init(&tmp->dupl_info[0].dupl_by_id, NULL);
     232                fd_list_init(&tmp->dupl_info[0].dupl_by_time, NULL);
     233        }
    128234        tmp->type = type;
    129235       
     
    156262}
    157263
    158 
    159264/* Decrease refcount on a client; the lock must be held when this function is called. */
    160265static void client_unlink(struct rgw_client * client)
     
    177282                /* Free the duplicate info */
    178283                for (idx=0; idx <= 1; idx++){
    179                         int i = 0;
    180                         for (i = 0; i < DUPLICATE_MESSAGES_BUFFER; i++) {
    181                                 if (client->duplicates_info[idx].msg_info[i].ans) {
    182                                         /* Free this RADIUS message */
    183                                         radius_msg_free(client->duplicates_info[idx].msg_info[i].ans);
    184                                         free(client->duplicates_info[idx].msg_info[i].ans);
    185                                 }
     284                        CHECK_POSIX_DO( pthread_mutex_lock( &client->dupl_info[idx].dupl_lock ), /* continue */ );
     285                       
     286                        while (!FD_IS_LIST_EMPTY(&client->dupl_info[idx].dupl_by_id)) {
     287                                struct req_info * r = (struct req_info *)(client->dupl_info[idx].dupl_by_id.next->o);
     288                                fd_list_unlink( &r->by_id );
     289                                fd_list_unlink( &r->by_time );
     290                                dupl_free_req_info(r);
    186291                        }
     292                       
     293                        CHECK_POSIX_DO( pthread_mutex_unlock( &client->dupl_info[idx].dupl_lock ), /* continue */ );
     294
    187295                }
    188296               
     
    222330                }
    223331/* Function to look for an existing rgw_client, or the previous element.
    224    The cli_mtx must be held when calling this function.
     332   The cli_rwl must be held for reading (at least) when calling this function.
    225333   Returns ENOENT if the matching client does not exist, and res points to the previous element in the list.
    226334   Returns EEXIST if the matching client is found, and res points to this element.
     
    270378        CHECK_PARAMS(ip_port && ref);
    271379       
    272         CHECK_POSIX( pthread_mutex_lock(&cli_mtx) );
     380        CHECK_POSIX( pthread_rwlock_rdlock(&cli_rwl) );
    273381
    274382        ret = client_search(ref, ip_port);
     
    280388        }
    281389       
    282         CHECK_POSIX( pthread_mutex_unlock(&cli_mtx) );
     390        CHECK_POSIX( pthread_rwlock_unlock(&cli_rwl) );
    283391       
    284392        return ret;
     
    287395int rgw_clients_check_dup(struct rgw_radius_msg_meta **msg, struct rgw_client *cli)
    288396{
    289         int p, i, dup = 0;
     397        int p, dup = 0;
     398        struct fd_list * li;
     399        struct req_info * r;
    290400       
    291401        TRACE_ENTRY("%p %p", msg, cli);
     
    298408                p = 1;
    299409       
    300         /* Check in the previous DUPLICATE_MESSAGES_BUFFER messages if we have received the same identifier / authenticator / port combination */
    301         for (i = cli->duplicates_info[p].cnt - 1; i >= cli->duplicates_info[p].cnt - DUPLICATE_MESSAGES_BUFFER; i--) {
    302                 if ( (cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].id == (*msg)->radius.hdr->identifier)
    303                   && (cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].port == (*msg)->port)
    304                   && !memcmp(&cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].auth[0], &(*msg)->radius.hdr->authenticator[0], 16)) {
    305                         /* We already received this request */
    306                         cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].nbdup++;
    307                         dup = 1;
    308                         TRACE_DEBUG(INFO, "Received duplicated RADIUS message (id: %02hhx, port: %hu, dup #%d).",
    309                                         (*msg)->radius.hdr->identifier,
    310                                         ntohs((*msg)->port),
    311                                         cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].nbdup);
    312                         if (cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].ans) {
    313                                 /* Resend the answer */
    314                                 CHECK_FCT_DO( rgw_servers_send((*msg)->serv_type,
    315                                                                 cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].ans->buf,
    316                                                                 cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].ans->buf_used,
    317                                                                 cli->sa,
    318                                                                 (*msg)->port),  );
    319                         }
    320                         rgw_msg_free(msg);
     410        CHECK_POSIX( pthread_mutex_lock( &cli->dupl_info[p].dupl_lock ) );
     411       
     412        /* Search if we have this message in our list */
     413        for (li = cli->dupl_info[p].dupl_by_id.next; li != &cli->dupl_info[p].dupl_by_id; li = li->next) {
     414                int cmp = 0;
     415                r = (struct req_info *)(li->o);
     416                if (r->id < (*msg)->radius.hdr->identifier)
     417                        continue;
     418                if (r->id > (*msg)->radius.hdr->identifier)
    321419                        break;
    322                 }
    323         }
    324        
    325         /* If we did no already receive this request, save it for later */
    326         if (!dup) {
    327                 /* It's a new request, save its data */
    328                 int i = cli->duplicates_info[p].cnt % DUPLICATE_MESSAGES_BUFFER;
    329                
    330                 cli->duplicates_info[p].msg_info[i].port = (*msg)->port;
    331                 cli->duplicates_info[p].msg_info[i].id   = (*msg)->radius.hdr->identifier;
    332                 memcpy(&cli->duplicates_info[p].msg_info[i].auth[0], &(*msg)->radius.hdr->authenticator[0], 16);
    333                 if (cli->duplicates_info[p].msg_info[i].ans) {
    334                         /* Free the old answer */
    335                         radius_msg_free(cli->duplicates_info[p].msg_info[i].ans);
    336                         free(cli->duplicates_info[p].msg_info[i].ans);
    337                         cli->duplicates_info[p].msg_info[i].ans = NULL;
    338                 }
    339                 cli->duplicates_info[p].msg_info[i].nbdup = 0;
     420                if (r->port < (*msg)->port)
     421                        continue;
     422                if (r->port > (*msg)->port)
     423                        break;
     424                cmp = memcmp(&r->auth[0], &(*msg)->radius.hdr->authenticator[0], 16);
     425                if (cmp < 0)
     426                        continue;
     427                if (cmp > 0);
     428                        break;
     429                dup = 1;
     430                break;
     431        }
     432       
     433        if (dup) {
     434                time_t now = time(NULL);
     435                r->nbdup += 1;
     436                TRACE_DEBUG(INFO, "Received duplicated RADIUS message (id: %02hhx, port: %hu, dup #%d, previously seen %d secs ago).",
     437                                r->id, ntohs(r->port), r->nbdup, now - r->received);
     438               
     439                if (r->ans) {
     440                        /* Resend the answer */
     441                        CHECK_FCT_DO( rgw_servers_send((*msg)->serv_type, r->ans->buf, r->ans->buf_used, cli->sa, r->port),  );
    340442                       
    341                 cli->duplicates_info[p].cnt += 1;
    342         }
     443                        /* Should we delete 'r' so that a further duplicate will again be converted to Diameter? */
     444                }
     445               
     446                /* Update the timestamp */
     447                r->received = now;
     448                fd_list_unlink(&r->by_time);
     449                fd_list_insert_before(&cli->dupl_info[p].dupl_by_time, &r->by_time); /* Move as last entry, since it is the most recent */
     450               
     451                /* Delete the request message */
     452                rgw_msg_free(msg);
     453               
     454        } else {
     455                /* The message was not a duplicate, we save it */
     456                /* li currently points the the next entry in list_by_id */
     457                CHECK_MALLOC_DO( r= dupl_new_req_info(*msg), { CHECK_POSIX_DO(pthread_mutex_unlock( &cli->dupl_info[p].dupl_lock ), ); return ENOMEM; } );
     458                fd_list_insert_before(li, &r->by_id);
     459                fd_list_insert_before(&cli->dupl_info[p].dupl_by_time, &r->by_time); /* it is the most recent */
     460        }
     461               
     462        CHECK_POSIX( pthread_mutex_unlock( &cli->dupl_info[p].dupl_lock ) );
    343463       
    344464        return 0;
    345465}
    346466
    347 /* Check that the NAS-IP-Adress or NAS-Identifier is coherent with the IP the packet was received from */
    348 /* Also update the client list of aliases if needed */
    349 /* NOTE: This function does nothing if the client is a RADIUS Proxy... */
    350467/* Check if the message has a valid authenticator, and update the meta-data accordingly */
    351468int rgw_clients_auth_check(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, uint8_t * req_auth)
     
    390507        CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &cache_orig_realm, ENOENT) );
    391508        CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Route-Record", &cache_route_record, ENOENT) );
     509       
     510        /* Create the thread that will purge old RADIUS duplicates */
     511        CHECK_POSIX( pthread_create( &dbt_expire, NULL, dupl_th, NULL) );
     512       
    392513        return 0;
    393514}
     
    396517/* The following function checks if a RADIUS message contains a valid NAS identifier, and initializes an empty Diameter
    397518 message with the appropriate routing information */
     519/* Check that the NAS-IP-Adress or NAS-Identifier is coherent with the IP the packet was received from */
     520/* Also update the client list of aliases if needed */
    398521int rgw_clients_create_origin(struct rgw_radius_msg_meta *msg, struct rgw_client * cli, struct msg ** diam)
    399522{
     
    714837        CHECK_PARAMS_DO(ref, return);
    715838       
    716         CHECK_POSIX_DO( pthread_mutex_lock(&cli_mtx),  );
     839        CHECK_POSIX_DO( pthread_rwlock_wrlock(&cli_rwl),  );
    717840        client_unlink(*ref);
    718841        *ref = NULL;
    719         CHECK_POSIX_DO( pthread_mutex_unlock(&cli_mtx), );
     842        CHECK_POSIX_DO( pthread_rwlock_unlock(&cli_rwl), );
    720843}
    721844
     
    739862       
    740863        /* Lock the lists */
    741         CHECK_POSIX( pthread_mutex_lock(&cli_mtx) );
     864        CHECK_POSIX( pthread_rwlock_wrlock(&cli_rwl) );
    742865       
    743866        /* Check if the same entry does not already exist */
     
    770893end:
    771894        /* release the lists */
    772         CHECK_POSIX( pthread_mutex_unlock(&cli_mtx) );
     895        CHECK_POSIX( pthread_rwlock_unlock(&cli_rwl) );
    773896       
    774897        return ret;
     
    791914                return;
    792915       
    793         CHECK_POSIX_DO( pthread_mutex_lock(&cli_mtx), /* ignore error */ );
     916        CHECK_POSIX_DO( pthread_rwlock_rdlock(&cli_rwl), /* ignore error */ );
    794917       
    795918        if (!FD_IS_LIST_EMPTY(&cli_ip))
     
    801924        dump_cli_list(&cli_ip6);
    802925               
    803         CHECK_POSIX_DO( pthread_mutex_unlock(&cli_mtx), /* ignore error */ );
     926        CHECK_POSIX_DO( pthread_rwlock_unlock(&cli_rwl), /* ignore error */ );
    804927}
    805928
     
    810933        TRACE_ENTRY();
    811934       
    812         CHECK_POSIX_DO( pthread_mutex_lock(&cli_mtx), /* ignore error */ );
    813        
     935        CHECK_POSIX_DO( pthread_rwlock_wrlock(&cli_rwl), /* ignore error */ );
     936       
     937        CHECK_FCT_DO( fd_thr_term(&dbt_expire), /* continue */ );
     938
    814939        /* empty the lists */
    815940        while ( ! FD_IS_LIST_EMPTY(&cli_ip) ) {
     
    824949        }
    825950       
    826         CHECK_POSIX_DO( pthread_mutex_unlock(&cli_mtx), /* ignore error */ );
     951        CHECK_POSIX_DO( pthread_rwlock_unlock(&cli_rwl), /* ignore error */ );
    827952       
    828953}
     
    830955int rgw_client_finish_send(struct radius_msg ** msg, struct rgw_radius_msg_meta * req, struct rgw_client * cli)
    831956{
    832         int p,i;
     957        int p;
     958        struct fd_list * li;
    833959       
    834960        TRACE_ENTRY("%p %p %p", msg, req, cli);
     
    856982        CHECK_FCT( rgw_servers_send(req->serv_type, (*msg)->buf, (*msg)->buf_used, cli->sa, req->port) );
    857983
    858         /* update the duplicate cache in rgw_clients */
     984        /* update the duplicate cache */
    859985        if (req->serv_type == RGW_PLG_TYPE_AUTH)
    860986                p = 0;
    861987        else
    862988                p = 1;
    863         for (i = cli->duplicates_info[p].cnt - 1; i >= cli->duplicates_info[p].cnt - DUPLICATE_MESSAGES_BUFFER; i--) {
    864                 /* Search the entry corresponding to the request */
    865                 if ( (cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].id == req->radius.hdr->identifier)
    866                   && (cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].port == req->port)
    867                   && !memcmp(&cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].auth[0], &req->radius.hdr->authenticator[0], 16)) {
    868                         /* This should not happen, but just in case */
    869                         if (cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].ans) {
    870                                 radius_msg_free(cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].ans);
    871                                 free(cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].ans);
    872                         }
    873                         /* Now save the answer message */
    874                         cli->duplicates_info[p].msg_info[i % DUPLICATE_MESSAGES_BUFFER].ans = *msg;
    875                         *msg = NULL;
     989       
     990        CHECK_POSIX( pthread_mutex_lock( &cli->dupl_info[p].dupl_lock ) );
     991       
     992        /* Search this message in our list */
     993        for (li = cli->dupl_info[p].dupl_by_id.next; li != &cli->dupl_info[p].dupl_by_id; li = li->next) {
     994                int cmp = 0;
     995                struct req_info * r = (struct req_info *)(li->o);
     996                if (r->id < req->radius.hdr->identifier)
     997                        continue;
     998                if (r->id > req->radius.hdr->identifier)
    876999                        break;
    877                 }
    878         }
    879        
    880         /* If we have not found the request in our circular buffer, it is probably too small */
     1000                if (r->port < req->port)
     1001                        continue;
     1002                if (r->port > req->port)
     1003                        break;
     1004                cmp = memcmp(&r->auth[0], &req->radius.hdr->authenticator[0], 16);
     1005                if (cmp < 0)
     1006                        continue;
     1007                if (cmp > 0);
     1008                        break;
     1009               
     1010                /* We have the request in our duplicate cache */
     1011                /* This should not happen, but just in case... */
     1012                if (r->ans) {
     1013                        radius_msg_free(r->ans);
     1014                        free(r->ans);
     1015                }
     1016               
     1017                /* Now save the message */
     1018                r->ans = *msg;
     1019                *msg = NULL;
     1020               
     1021                /* Update the timestamp */
     1022                {
     1023                        time_t now = time(NULL);
     1024                        TRACE_DEBUG(FULL, "Sent RADIUS answer %d seconds after the request was received.", now - r->received);
     1025                        r->received = now;
     1026                        fd_list_unlink(&r->by_time); /* Move as last entry, since it is the most recent */
     1027                        fd_list_insert_before(&cli->dupl_info[p].dupl_by_time, &r->by_time);
     1028                }
     1029                break;
     1030        }
     1031               
     1032        CHECK_POSIX( pthread_mutex_unlock( &cli->dupl_info[p].dupl_lock ) );
     1033       
     1034        /* If we have not found the request in our list, the purge time is probably too small */
    8811035        if (*msg) {
    882                 TODO("Implement a dynamic list for RADIUS duplicates detection based on expiry time instead of number of messages");
    883                 TRACE_DEBUG(INFO, "The circular buffer has circled before the Diameter answer was received, you should definitely increase DUPLICATE_MESSAGES_BUFFER value.");
    884                 /* We don't re-save the value */
     1036                TODO("Augment the purge time...");
     1037                /* If we receive the duplicate request again, it will be converted to Diameter... */
    8851038                radius_msg_free(*msg);
    8861039                free(*msg);
Note: See TracChangeset for help on using the changeset viewer.