Navigation


source: freeDiameter/libfdcore/peers.c @ 706:4ffbc9f1e922

Last change on this file since 706:4ffbc9f1e922 was 706:4ffbc9f1e922, checked in by Sebastien Decugis <sdecugis@nict.go.jp>, 11 years ago

Large UNTESTED commit with the following changes:

  • Improved DiameterIdentity? handling (esp. interationalization issues), and improve efficiency of some string operations in peers, sessions, and dictionary modules (closes #7)
  • Cleanup in the session module to free only unreferenced sessions (#16)
  • Removed fd_cpu_flush_cache(), replaced by more robust alternatives.
  • Improved peer state machine algorithm to counter SCTP multistream race condition.
File size: 19.8 KB
Line 
1/*********************************************************************************************************
2* Software License Agreement (BSD License)                                                               *
3* Author: Sebastien Decugis <sdecugis@nict.go.jp>                                                        *
4*                                                                                                        *
5* Copyright (c) 2011, WIDE Project and NICT                                                              *
6* All rights reserved.                                                                                   *
7*                                                                                                        *
8* Redistribution and use of this software in source and binary forms, with or without modification, are  *
9* permitted provided that the following conditions are met:                                              *
10*                                                                                                        *
11* * Redistributions of source code must retain the above                                                 *
12*   copyright notice, this list of conditions and the                                                    *
13*   following disclaimer.                                                                                *
14*                                                                                                        *
15* * Redistributions in binary form must reproduce the above                                              *
16*   copyright notice, this list of conditions and the                                                    *
17*   following disclaimer in the documentation and/or other                                               *
18*   materials provided with the distribution.                                                            *
19*                                                                                                        *
20* * Neither the name of the WIDE Project or NICT nor the                                                 *
21*   names of its contributors may be used to endorse or                                                  *
22*   promote products derived from this software without                                                  *
23*   specific prior written permission of WIDE Project and                                                *
24*   NICT.                                                                                                *
25*                                                                                                        *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT     *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS    *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                                             *
34*********************************************************************************************************/
35
36#include "fdcore-internal.h"
37
38/* Global list of peers */
39struct fd_list   fd_g_peers = FD_LIST_INITIALIZER(fd_g_peers);
40pthread_rwlock_t fd_g_peers_rw = PTHREAD_RWLOCK_INITIALIZER;
41
42/* List of active peers */
43struct fd_list   fd_g_activ_peers = FD_LIST_INITIALIZER(fd_g_activ_peers);      /* peers linked by their p_actives oredered by p_diamid */
44pthread_rwlock_t fd_g_activ_peers_rw = PTHREAD_RWLOCK_INITIALIZER;
45
46/* List of validation callbacks (registered with fd_peer_validate_register) */
47static struct fd_list validators = FD_LIST_INITIALIZER(validators);     /* list items are simple fd_list with "o" pointing to the callback */
48static pthread_rwlock_t validators_rw = PTHREAD_RWLOCK_INITIALIZER;
49
50
51/* Alloc / reinit a peer structure. if *ptr is not NULL, it must already point to a valid struct fd_peer. */
52int fd_peer_alloc(struct fd_peer ** ptr)
53{
54        struct fd_peer *p;
55       
56        TRACE_ENTRY("%p", ptr);
57        CHECK_PARAMS(ptr);
58       
59        if (*ptr) {
60                p = *ptr;
61        } else {
62                CHECK_MALLOC( p = malloc(sizeof(struct fd_peer)) );
63                *ptr = p;
64        }
65       
66        /* Now initialize the content */
67        memset(p, 0, sizeof(struct fd_peer));
68       
69        fd_list_init(&p->p_hdr.chain, p);
70       
71        fd_list_init(&p->p_hdr.info.pi_endpoints, p);
72        fd_list_init(&p->p_hdr.info.runtime.pir_apps, p);
73       
74        p->p_eyec = EYEC_PEER;
75        CHECK_POSIX( pthread_mutex_init(&p->p_state_mtx, NULL) );
76       
77        fd_list_init(&p->p_actives, p);
78        fd_list_init(&p->p_expiry, p);
79        CHECK_FCT( fd_fifo_new(&p->p_tosend) );
80        p->p_hbh = lrand48();
81       
82        fd_list_init(&p->p_sr.srs, p);
83        fd_list_init(&p->p_sr.exp, p);
84        CHECK_POSIX( pthread_mutex_init(&p->p_sr.mtx, NULL) );
85        CHECK_POSIX( pthread_cond_init(&p->p_sr.cnd, NULL) );
86       
87        fd_list_init(&p->p_connparams, p);
88       
89        return 0;
90}
91
92/* Add a new peer entry */
93int fd_peer_add ( struct peer_info * info, char * orig_dbg, void (*cb)(struct peer_info *, void *), void * cb_data )
94{
95        struct fd_peer *p = NULL;
96        struct fd_list * li;
97        int ret = 0;
98       
99        TRACE_ENTRY("%p %p %p %p", info, orig_dbg, cb, cb_data);
100        CHECK_PARAMS(info && info->pi_diamid);
101       
102        if (info->config.pic_realm) {
103                if (!fd_os_is_valid_DiameterIdentity((os0_t)info->config.pic_realm, strlen(info->config.pic_realm))) {
104                        TRACE_DEBUG(INFO, "'%s' is not a valid DiameterIdentity.", info->config.pic_realm);
105                        return EINVAL;
106                }
107        }
108       
109        /* Create a structure to contain the new peer information */
110        CHECK_FCT( fd_peer_alloc(&p) );
111       
112        /* Copy the informations from the parameters received */
113        p->p_hdr.info.pi_diamid = info->pi_diamid;
114        CHECK_FCT( fd_os_validate_DiameterIdentity(&p->p_hdr.info.pi_diamid, &p->p_hdr.info.pi_diamidlen, 1) );
115       
116        memcpy( &p->p_hdr.info.config, &info->config, sizeof(p->p_hdr.info.config) );
117       
118        /* Duplicate the strings if provided */
119        if (info->config.pic_realm) {
120                CHECK_MALLOC( p->p_hdr.info.config.pic_realm = strdup(info->config.pic_realm) );
121        }
122        if (info->config.pic_priority) {
123                CHECK_MALLOC( p->p_hdr.info.config.pic_priority = strdup(info->config.pic_priority) );
124        }
125       
126        /* Move the list of endpoints into the peer */
127        if (info->pi_endpoints.next)
128                while (!FD_IS_LIST_EMPTY( &info->pi_endpoints ) ) {
129                        li = info->pi_endpoints.next;
130                        fd_list_unlink(li);
131                        fd_list_insert_before(&p->p_hdr.info.pi_endpoints, li);
132                }
133       
134        /* The internal data */
135        if (orig_dbg) {
136                CHECK_MALLOC( p->p_dbgorig = strdup(orig_dbg) );
137        } else {
138                CHECK_MALLOC( p->p_dbgorig = strdup("unspecified") );
139        }
140        p->p_cb = cb;
141        p->p_cb_data = cb_data;
142       
143        /* Ok, now check if we don't already have an entry with the same Diameter Id, and insert this one */
144        CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_peers_rw) );
145       
146        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
147                struct fd_peer * next = (struct fd_peer *)li;
148                int cmp = fd_os_almostcasecmp( p->p_hdr.info.pi_diamid, p->p_hdr.info.pi_diamidlen, 
149                                                next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen );
150                if (cmp > 0)
151                        continue;
152                if (cmp == 0)
153                        ret = EEXIST;
154                break;
155        }
156       
157        /* We can insert the new peer object */
158        if (! ret)
159                do {
160                        /* Update expiry list */
161                        CHECK_FCT_DO( ret = fd_p_expi_update( p ), break );
162
163                        /* Insert the new element in the list */
164                        fd_list_insert_before( li, &p->p_hdr.chain );
165                } while (0);
166
167        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
168        if (ret) {
169                CHECK_FCT( fd_peer_free(&p) );
170        } else {
171                CHECK_FCT( fd_psm_begin(p) );
172        }
173        return ret;
174}
175
176/* Search for a peer */
177int fd_peer_getbyid( DiamId_t diamid, size_t diamidlen, int igncase, struct peer_hdr ** peer )
178{
179        struct fd_list * li;
180        TRACE_ENTRY("%p %zd %d %p", diamid, diamidlen, igncase, peer);
181        CHECK_PARAMS( diamid && diamidlen && peer );
182       
183        *peer = NULL;
184       
185        /* Search in the list */
186        CHECK_POSIX( pthread_rwlock_rdlock(&fd_g_peers_rw) );
187        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
188                struct fd_peer * next = (struct fd_peer *)li;
189                int cmp;
190                if (igncase)
191                        cmp = fd_os_almostcasecmp( diamid, diamidlen, next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen );
192                else
193                        cmp = fd_os_cmp( diamid, diamidlen, next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen );
194                if (cmp > 0)
195                        continue;
196                if (cmp == 0)
197                        *peer = &next->p_hdr;
198                break;
199        }
200        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
201       
202        return 0;
203}
204
205
206#define free_null( _v )         \
207        if (_v) {               \
208                free(_v);       \
209                (_v) = NULL;    \
210        }
211       
212#define free_list( _l )                                                 \
213        while (!FD_IS_LIST_EMPTY(_l)) {                                 \
214                struct fd_list * __li = ((struct fd_list *)(_l))->next; \
215                fd_list_unlink(__li);                                   \
216                free(__li);                                             \
217        }
218
219/* Empty the lists of p_tosend and p_sentreq messages */
220void fd_peer_failover_msg(struct fd_peer * peer)
221{
222        struct msg *m;
223        TRACE_ENTRY("%p", peer);
224        CHECK_PARAMS_DO(CHECK_PEER(peer), return);
225       
226        /* Requeue all messages in the "out" queue */
227        while ( fd_fifo_tryget(peer->p_tosend, &m) == 0 ) {
228                CHECK_FCT_DO(fd_fifo_post(fd_g_outgoing, &m), 
229                        {
230                                /* fallback: destroy the message */
231                                fd_msg_log(FD_MSG_LOG_DROPPED, m, "Internal error: unable to requeue this message during failover process");
232                                CHECK_FCT_DO(fd_msg_free(m), /* What can we do more? */)
233                        } );
234        }
235       
236        /* Requeue all routable sent requests */
237        fd_p_sr_failover(&peer->p_sr);
238       
239        /* Done */
240        return;
241}
242
243/* Destroy a structure once cleanups have been performed (fd_psm_abord, ...) */
244int fd_peer_free(struct fd_peer ** ptr)
245{
246        struct fd_peer *p;
247       
248        TRACE_ENTRY("%p", ptr);
249        CHECK_PARAMS(ptr);
250        p = *ptr;
251        *ptr = NULL;
252        CHECK_PARAMS(p);
253       
254        CHECK_PARAMS( FD_IS_LIST_EMPTY(&p->p_hdr.chain) );
255       
256        free_null(p->p_hdr.info.pi_diamid);
257       
258        free_null(p->p_hdr.info.config.pic_realm); 
259        free_null(p->p_hdr.info.config.pic_priority); 
260       
261        free_null(p->p_hdr.info.runtime.pir_realm);
262        free_null(p->p_hdr.info.runtime.pir_prodname);
263        free_list( &p->p_hdr.info.runtime.pir_apps );
264       
265        free_list( &p->p_hdr.info.pi_endpoints );
266       
267        free_null(p->p_dbgorig);
268       
269        fd_list_unlink(&p->p_expiry);
270        fd_list_unlink(&p->p_actives);
271       
272        CHECK_FCT_DO( fd_fifo_del(&p->p_tosend), /* continue */ );
273        CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_state_mtx), /* continue */);
274        CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_sr.mtx), /* continue */);
275        CHECK_POSIX_DO( pthread_cond_destroy(&p->p_sr.cnd), /* continue */);
276       
277        /* If the callback is still around... */
278        if (p->p_cb)
279                (*p->p_cb)(NULL, p->p_cb_data);
280       
281        /* Free the structure */
282        free(p);
283        return 0;
284}
285
286/* Terminate peer module (destroy all peers, first gently, then violently) */
287int fd_peer_fini()
288{
289        struct fd_list * li;
290        struct fd_list purge = FD_LIST_INITIALIZER(purge); /* Store zombie peers here */
291        int list_empty;
292        struct timespec wait_until, now;
293       
294        TRACE_ENTRY();
295       
296        CHECK_FCT_DO(fd_p_expi_fini(), /* continue */);
297       
298        TRACE_DEBUG(INFO, "Sending terminate signal to all peer connections");
299       
300        CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
301        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
302                struct fd_peer * peer = (struct fd_peer *)li->o;
303               
304                if (fd_peer_getstate(peer) != STATE_ZOMBIE) {
305                        CHECK_FCT_DO( fd_psm_terminate(peer, "REBOOTING"), /* continue */ );
306                } else {
307                        li = li->prev; /* to avoid breaking the loop */
308                        fd_list_unlink(&peer->p_hdr.chain);
309                        fd_list_insert_before(&purge, &peer->p_hdr.chain);
310                }
311        }
312        list_empty = FD_IS_LIST_EMPTY(&fd_g_peers);
313        CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
314       
315        if (!list_empty) {
316                CHECK_SYS(  clock_gettime(CLOCK_REALTIME, &now)  );
317                TRACE_DEBUG(INFO, "Waiting for connections shutdown... (%d sec max)", DPR_TIMEOUT + 1);
318                wait_until.tv_sec  = now.tv_sec + DPR_TIMEOUT + 1;
319                wait_until.tv_nsec = now.tv_nsec;
320        }
321       
322        while ((!list_empty) && (TS_IS_INFERIOR(&now, &wait_until))) {
323               
324                /* Allow the PSM(s) to execute */
325                usleep(100000);
326               
327                /* Remove zombie peers */
328                CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
329                for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
330                        struct fd_peer * peer = (struct fd_peer *)li->o;
331                        if (fd_peer_getstate(peer) == STATE_ZOMBIE) {
332                                li = li->prev; /* to avoid breaking the loop */
333                                fd_list_unlink(&peer->p_hdr.chain);
334                                fd_list_insert_before(&purge, &peer->p_hdr.chain);
335                        }
336                }
337                list_empty = FD_IS_LIST_EMPTY(&fd_g_peers);
338                CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
339                CHECK_SYS(  clock_gettime(CLOCK_REALTIME, &now)  );
340        }
341       
342        if (!list_empty) {
343                TRACE_DEBUG(INFO, "Forcing connections shutdown");
344                CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
345                while (!FD_IS_LIST_EMPTY(&fd_g_peers)) {
346                        struct fd_peer * peer = (struct fd_peer *)(fd_g_peers.next->o);
347                        fd_psm_abord(peer);
348                        fd_list_unlink(&peer->p_hdr.chain);
349                        fd_list_insert_before(&purge, &peer->p_hdr.chain);
350                }
351                CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
352        }
353       
354        /* Free memory objects of all peers */
355        while (!FD_IS_LIST_EMPTY(&purge)) {
356                struct fd_peer * peer = (struct fd_peer *)(purge.next->o);
357                fd_list_unlink(&peer->p_hdr.chain);
358                fd_peer_free(&peer);
359        }
360       
361        /* Now empty the validators list */
362        CHECK_FCT_DO( pthread_rwlock_wrlock(&validators_rw), /* continue */ );
363        while (!FD_IS_LIST_EMPTY( &validators )) {
364                struct fd_list * v = validators.next;
365                fd_list_unlink(v);
366                free(v);
367        }
368        CHECK_FCT_DO( pthread_rwlock_unlock(&validators_rw), /* continue */ );
369       
370        return 0;
371}
372
373/* Dump info of one peer */
374void fd_peer_dump(struct fd_peer * peer, int details)
375{
376        if (peer->p_eyec != EYEC_PEER) {
377                fd_log_debug("  Invalid peer @ %p !\n", peer);
378                return;
379        }
380
381        fd_log_debug(">  %s\t%s", STATE_STR(fd_peer_getstate(peer)), peer->p_hdr.info.pi_diamid);
382        if (details > INFO) {
383                fd_log_debug("\t(rlm:%s)", peer->p_hdr.info.runtime.pir_realm ?: "<unknown>");
384                if (peer->p_hdr.info.runtime.pir_prodname)
385                        fd_log_debug("\t['%s' %u]", peer->p_hdr.info.runtime.pir_prodname, peer->p_hdr.info.runtime.pir_firmrev);
386        }
387        fd_log_debug("\n");
388        if (details > FULL) {
389                /* Dump all info */
390                fd_log_debug("\tEntry origin : %s\n", peer->p_dbgorig?: "not set");
391                fd_log_debug("\tConfig flags : %s%s%s%s%s - %s%s%s\n", 
392                                peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_DEFAULT ? "" :
393                                        (peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP ? "IP." : "IPv6."),
394                                peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_DEFAULT ? "" :
395                                        (peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_TCP ? "TCP." : "SCTP."),
396                                peer->p_hdr.info.config.pic_flags.alg ? "PrefTCP." : "",
397                                peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE ? "NoTLSok" :"",
398                                peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD ? "OldTLS" :"",
399                                peer->p_hdr.info.config.pic_flags.exp ? "Expire." : "",
400                                peer->p_hdr.info.config.pic_flags.persist ? "Persist." : ""
401                                );
402                fd_log_debug("\tLifetime : %d sec\n", peer->p_hdr.info.config.pic_lft);
403        }
404}
405
406/* Dump the list of peers */
407void fd_peer_dump_list(int details)
408{
409        struct fd_list * li;
410       
411        fd_log_debug("Dumping list of peers :\n");
412        CHECK_FCT_DO( pthread_rwlock_rdlock(&fd_g_peers_rw), /* continue */ );
413       
414        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
415                struct fd_peer * np = (struct fd_peer *)li->o;
416                fd_peer_dump(np, details);
417        }
418       
419        CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
420}
421
422static struct dict_object *avp_oh_model = NULL;
423static pthread_mutex_t cache_avp_lock = PTHREAD_MUTEX_INITIALIZER;
424
425/* Handle an incoming CER request on a new connection */
426int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx )
427{
428        struct msg * msg;
429        struct avp *avp_oh;
430        struct avp_hdr * avp_hdr;
431        struct fd_list * li;
432        int found = 0;
433        int ret = 0;
434        struct fd_peer * peer;
435        struct cnx_incoming * ev_data;
436       
437        TRACE_ENTRY("%p %p", cer, cnx);
438        CHECK_PARAMS(cer && *cer && cnx && *cnx);
439       
440        msg = *cer; 
441       
442        /* If needed, resolve the dictioanry model for Origin-Host */
443        CHECK_POSIX( pthread_mutex_lock(&cache_avp_lock) );
444        if (!avp_oh_model) {
445                avp_code_t code = AC_ORIGIN_HOST;
446                int ret;
447                CHECK_FCT_DO( ret = fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE, &code, &avp_oh_model, ENOENT),
448                        { CHECK_POSIX( pthread_mutex_unlock(&cache_avp_lock) ); return ret; } );
449        }
450        CHECK_POSIX( pthread_mutex_unlock(&cache_avp_lock) );
451       
452        /* Find the Diameter Identity of the remote peer in the message */
453        CHECK_FCT( fd_msg_search_avp ( msg, avp_oh_model, &avp_oh ) );
454        ASSERT(avp_oh); /* otherwise it should not have passed rules validation, right? */
455        CHECK_FCT( fd_msg_avp_hdr ( avp_oh, &avp_hdr ) );
456       
457        /* First, check if the Origin-Host value  */
458        if (!fd_os_is_valid_DiameterIdentity(avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len)) {
459                TRACE_DEBUG(INFO, "Received new CER with invalid \\0 in its Origin-Host");
460                CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, cer, MSGFL_ANSW_ERROR ) );
461                CHECK_FCT( fd_msg_rescode_set(*cer, "ER_DIAMETER_INVALID_AVP_VALUE", 
462                                                        "Your Origin-Host contains invalid characters.", avp_oh, 1 ) );
463                CHECK_FCT( fd_out_send(cer, *cnx, NULL, FD_CNX_ORDERED) );
464                return EINVAL;
465        }
466       
467        /* Search if we already have this peer id in our list. We take directly the write lock so that we don't need to upgrade if it is a new peer.
468         * There is space for a small optimization here if needed.
469         */
470        CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_peers_rw) );
471       
472        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
473                int cmp;
474                peer = (struct fd_peer *)li->o;
475                cmp = fd_os_almostcasecmp( avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len, peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen );
476                if (cmp > 0)
477                        continue;
478                if (cmp == 0)
479                        found = 1;
480                break;
481        }
482       
483        if (!found) {
484                /* Create a new peer entry for this new remote peer */
485                peer = NULL;
486                CHECK_FCT_DO( ret = fd_peer_alloc(&peer), goto out );
487               
488                /* Set the peer Diameter Id and the responder flag parameters */
489                CHECK_MALLOC_DO( peer->p_hdr.info.pi_diamid = os0dup(avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len), 
490                        { ret = ENOMEM; goto out; } );
491                peer->p_hdr.info.pi_diamidlen = avp_hdr->avp_value->os.len;
492                CHECK_MALLOC_DO( peer->p_dbgorig = strdup(fd_cnx_getid(*cnx)), { ret = ENOMEM; goto out; } );
493                peer->p_flags.pf_responder = 1;
494                peer->p_flags.pf_delete = 1;
495               
496                /* Set this peer to expire on inactivity */
497                peer->p_hdr.info.config.pic_flags.exp   = PI_EXP_INACTIVE;
498                peer->p_hdr.info.config.pic_lft         = 3600; /* 1 hour without any message
499                -- RFC3539 states that this must not be inferior to BRINGDOWN_INTERVAL = 5 minutes */
500               
501                /* Insert the new peer in the list (the PSM will take care of setting the expiry after validation) */
502                fd_list_insert_before( li, &peer->p_hdr.chain );
503               
504                /* Start the PSM, which will receive the event bellow */
505                CHECK_FCT_DO( ret = fd_psm_begin(peer), goto out );
506        } else {
507                /* Check if the peer is in zombie state */
508                if (fd_peer_getstate(peer) == STATE_ZOMBIE) {
509                        /* Re-activate the peer */
510                        if (peer->p_hdr.info.config.pic_flags.exp)
511                                peer->p_flags.pf_responder = 1;
512                        CHECK_POSIX_DO( pthread_mutex_lock(&peer->p_state_mtx), );
513                        peer->p_state = STATE_NEW;
514                        CHECK_POSIX_DO( pthread_mutex_unlock(&peer->p_state_mtx), );
515                        peer->p_flags.pf_localterm = 0;
516                        CHECK_FCT_DO( ret = fd_psm_begin(peer), goto out );
517                }
518        }
519       
520        /* Send the new connection event to the PSM */
521        CHECK_MALLOC_DO( ev_data = malloc(sizeof(struct cnx_incoming)), { ret = ENOMEM; goto out; } );
522        memset(ev_data, 0, sizeof(ev_data));
523       
524        ev_data->cer = msg;
525        ev_data->cnx = *cnx;
526        ev_data->validate = !found;
527       
528        CHECK_FCT_DO( ret = fd_event_send(peer->p_events, FDEVP_CNX_INCOMING, sizeof(ev_data), ev_data), goto out );
529       
530out:   
531        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
532
533        if (ret == 0) {
534                /* Reset the "out" parameters, so that they are not cleanup on function return. */
535                *cer = NULL;
536                *cnx = NULL;
537        }
538       
539        return ret;
540}
541
542/* Save a callback to accept / reject incoming unknown peers */
543int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */, int (**cb2)(struct peer_info *)) )
544{
545        struct fd_list * v;
546       
547        TRACE_ENTRY("%p", peer_validate);
548        CHECK_PARAMS(peer_validate);
549       
550        /* Alloc a new entry */
551        CHECK_MALLOC( v = malloc(sizeof(struct fd_list)) );
552        fd_list_init( v, peer_validate );
553       
554        /* Add at the beginning of the list */
555        CHECK_FCT( pthread_rwlock_wrlock(&validators_rw) );
556        fd_list_insert_after(&validators, v);
557        CHECK_FCT( pthread_rwlock_unlock(&validators_rw));
558       
559        /* Done! */
560        return 0;
561}
562
563/* Validate a peer by calling the callbacks in turn -- return 0 if the peer is validated, ! 0 in case of error (>0) or if the peer is rejected (-1) */
564int fd_peer_validate( struct fd_peer * peer )
565{
566        int ret = 0;
567        struct fd_list * v;
568       
569        CHECK_FCT( pthread_rwlock_rdlock(&validators_rw) );
570        for (v = validators.next; v != &validators; v = v->next) {
571                int auth = 0;
572                pthread_cleanup_push(fd_cleanup_rwlock, &validators_rw);
573                CHECK_FCT_DO( ret = ((int(*)(struct peer_info *, int *, int (**)(struct peer_info *)))(v->o)) (&peer->p_hdr.info, &auth, &peer->p_cb2),  );
574                pthread_cleanup_pop(0);
575                if (ret)
576                        goto out;
577                if (auth) {
578                        ret = (auth > 0) ? 0 : -1;
579                        goto out;
580                }
581                peer->p_cb2 = NULL;
582        }
583       
584        /* No callback has given a firm result, the default is to reject */
585        ret = -1;
586out:
587        CHECK_FCT( pthread_rwlock_unlock(&validators_rw));
588        return ret;
589}
Note: See TracBrowser for help on using the repository browser.