Navigation


source: freeDiameter/libfdcore/peers.c @ 738:d666051658bd

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

Fix broken 'almostcasecmp' logic

File size: 20.2 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, *li_inf;
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        li_inf = &fd_g_peers;
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 cont;
149                int cmp = fd_os_almostcasesrch( p->p_hdr.info.pi_diamid, p->p_hdr.info.pi_diamidlen, 
150                                                next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen,
151                                                &cont );
152                if (cmp < 0)
153                        li_inf = li;
154               
155                if (cmp == 0) {
156                        ret = EEXIST;
157                        break;
158                }
159                if (!cont)
160                        break;
161        }
162       
163        /* We can insert the new peer object */
164        if (! ret)
165                do {
166                        /* Update expiry list */
167                        CHECK_FCT_DO( ret = fd_p_expi_update( p ), break );
168
169                        /* Insert the new element in the list */
170                        fd_list_insert_after( li_inf, &p->p_hdr.chain );
171                } while (0);
172
173        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
174        if (ret) {
175                CHECK_FCT( fd_peer_free(&p) );
176        } else {
177                CHECK_FCT( fd_psm_begin(p) );
178        }
179        return ret;
180}
181
182/* Search for a peer */
183int fd_peer_getbyid( DiamId_t diamid, size_t diamidlen, int igncase, struct peer_hdr ** peer )
184{
185        struct fd_list * li;
186        TRACE_ENTRY("%p %zd %d %p", diamid, diamidlen, igncase, peer);
187        CHECK_PARAMS( diamid && diamidlen && peer );
188       
189        *peer = NULL;
190       
191        /* Search in the list */
192        CHECK_POSIX( pthread_rwlock_rdlock(&fd_g_peers_rw) );
193        if (igncase)
194                for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
195                        struct fd_peer * next = (struct fd_peer *)li;
196                        int cmp, cont;
197                        cmp = fd_os_almostcasesrch( diamid, diamidlen, next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen, &cont );
198                        if (cmp == 0) {
199                                *peer = &next->p_hdr;
200                                break;
201                        }
202                        if (!cont)
203                                break;
204                }
205        else
206                for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
207                        struct fd_peer * next = (struct fd_peer *)li;
208                        int cmp = fd_os_cmp( diamid, diamidlen, next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen );
209                        if (cmp > 0)
210                                continue;
211                        if (cmp == 0)
212                                *peer = &next->p_hdr;
213                        break;
214                }
215        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
216       
217        return 0;
218}
219
220
221#define free_null( _v )         \
222        if (_v) {               \
223                free(_v);       \
224                (_v) = NULL;    \
225        }
226       
227#define free_list( _l )                                                 \
228        while (!FD_IS_LIST_EMPTY(_l)) {                                 \
229                struct fd_list * __li = ((struct fd_list *)(_l))->next; \
230                fd_list_unlink(__li);                                   \
231                free(__li);                                             \
232        }
233
234/* Empty the lists of p_tosend and p_sentreq messages */
235void fd_peer_failover_msg(struct fd_peer * peer)
236{
237        struct msg *m;
238        TRACE_ENTRY("%p", peer);
239        CHECK_PARAMS_DO(CHECK_PEER(peer), return);
240       
241        /* Requeue all messages in the "out" queue */
242        while ( fd_fifo_tryget(peer->p_tosend, &m) == 0 ) {
243                CHECK_FCT_DO(fd_fifo_post(fd_g_outgoing, &m), 
244                        {
245                                /* fallback: destroy the message */
246                                fd_msg_log(FD_MSG_LOG_DROPPED, m, "Internal error: unable to requeue this message during failover process");
247                                CHECK_FCT_DO(fd_msg_free(m), /* What can we do more? */)
248                        } );
249        }
250       
251        /* Requeue all routable sent requests */
252        fd_p_sr_failover(&peer->p_sr);
253       
254        /* Done */
255        return;
256}
257
258/* Destroy a structure once cleanups have been performed (fd_psm_abord, ...) */
259int fd_peer_free(struct fd_peer ** ptr)
260{
261        struct fd_peer *p;
262       
263        TRACE_ENTRY("%p", ptr);
264        CHECK_PARAMS(ptr);
265        p = *ptr;
266        *ptr = NULL;
267        CHECK_PARAMS(p);
268       
269        CHECK_PARAMS( FD_IS_LIST_EMPTY(&p->p_hdr.chain) );
270       
271        free_null(p->p_hdr.info.pi_diamid);
272       
273        free_null(p->p_hdr.info.config.pic_realm); 
274        free_null(p->p_hdr.info.config.pic_priority); 
275       
276        free_null(p->p_hdr.info.runtime.pir_realm);
277        free_null(p->p_hdr.info.runtime.pir_prodname);
278        free_list( &p->p_hdr.info.runtime.pir_apps );
279       
280        free_list( &p->p_hdr.info.pi_endpoints );
281       
282        free_null(p->p_dbgorig);
283       
284        fd_list_unlink(&p->p_expiry);
285        fd_list_unlink(&p->p_actives);
286       
287        CHECK_FCT_DO( fd_fifo_del(&p->p_tosend), /* continue */ );
288        CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_state_mtx), /* continue */);
289        CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_sr.mtx), /* continue */);
290        CHECK_POSIX_DO( pthread_cond_destroy(&p->p_sr.cnd), /* continue */);
291       
292        /* If the callback is still around... */
293        if (p->p_cb)
294                (*p->p_cb)(NULL, p->p_cb_data);
295       
296        /* Free the structure */
297        free(p);
298        return 0;
299}
300
301/* Terminate peer module (destroy all peers, first gently, then violently) */
302int fd_peer_fini()
303{
304        struct fd_list * li;
305        struct fd_list purge = FD_LIST_INITIALIZER(purge); /* Store zombie peers here */
306        int list_empty;
307        struct timespec wait_until, now;
308       
309        TRACE_ENTRY();
310       
311        CHECK_FCT_DO(fd_p_expi_fini(), /* continue */);
312       
313        TRACE_DEBUG(INFO, "Sending terminate signal to all peer connections");
314       
315        CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
316        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
317                struct fd_peer * peer = (struct fd_peer *)li->o;
318               
319                if (fd_peer_getstate(peer) != STATE_ZOMBIE) {
320                        CHECK_FCT_DO( fd_psm_terminate(peer, "REBOOTING"), /* continue */ );
321                } else {
322                        li = li->prev; /* to avoid breaking the loop */
323                        fd_list_unlink(&peer->p_hdr.chain);
324                        fd_list_insert_before(&purge, &peer->p_hdr.chain);
325                }
326        }
327        list_empty = FD_IS_LIST_EMPTY(&fd_g_peers);
328        CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
329       
330        if (!list_empty) {
331                CHECK_SYS(  clock_gettime(CLOCK_REALTIME, &now)  );
332                TRACE_DEBUG(INFO, "Waiting for connections shutdown... (%d sec max)", DPR_TIMEOUT + 1);
333                wait_until.tv_sec  = now.tv_sec + DPR_TIMEOUT + 1;
334                wait_until.tv_nsec = now.tv_nsec;
335        }
336       
337        while ((!list_empty) && (TS_IS_INFERIOR(&now, &wait_until))) {
338               
339                /* Allow the PSM(s) to execute */
340                usleep(100000);
341               
342                /* Remove zombie peers */
343                CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
344                for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
345                        struct fd_peer * peer = (struct fd_peer *)li->o;
346                        if (fd_peer_getstate(peer) == STATE_ZOMBIE) {
347                                li = li->prev; /* to avoid breaking the loop */
348                                fd_list_unlink(&peer->p_hdr.chain);
349                                fd_list_insert_before(&purge, &peer->p_hdr.chain);
350                        }
351                }
352                list_empty = FD_IS_LIST_EMPTY(&fd_g_peers);
353                CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
354                CHECK_SYS(  clock_gettime(CLOCK_REALTIME, &now)  );
355        }
356       
357        if (!list_empty) {
358                TRACE_DEBUG(INFO, "Forcing connections shutdown");
359                CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
360                while (!FD_IS_LIST_EMPTY(&fd_g_peers)) {
361                        struct fd_peer * peer = (struct fd_peer *)(fd_g_peers.next->o);
362                        fd_psm_abord(peer);
363                        fd_list_unlink(&peer->p_hdr.chain);
364                        fd_list_insert_before(&purge, &peer->p_hdr.chain);
365                }
366                CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
367        }
368       
369        /* Free memory objects of all peers */
370        while (!FD_IS_LIST_EMPTY(&purge)) {
371                struct fd_peer * peer = (struct fd_peer *)(purge.next->o);
372                fd_list_unlink(&peer->p_hdr.chain);
373                fd_peer_free(&peer);
374        }
375       
376        /* Now empty the validators list */
377        CHECK_FCT_DO( pthread_rwlock_wrlock(&validators_rw), /* continue */ );
378        while (!FD_IS_LIST_EMPTY( &validators )) {
379                struct fd_list * v = validators.next;
380                fd_list_unlink(v);
381                free(v);
382        }
383        CHECK_FCT_DO( pthread_rwlock_unlock(&validators_rw), /* continue */ );
384       
385        return 0;
386}
387
388/* Dump info of one peer */
389void fd_peer_dump(struct fd_peer * peer, int details)
390{
391        if (peer->p_eyec != EYEC_PEER) {
392                fd_log_debug("  Invalid peer @ %p !\n", peer);
393                return;
394        }
395
396        fd_log_debug(">  %s\t%s", STATE_STR(fd_peer_getstate(peer)), peer->p_hdr.info.pi_diamid);
397        if (details > INFO) {
398                fd_log_debug("\t(rlm:%s)", peer->p_hdr.info.runtime.pir_realm ?: "<unknown>");
399                if (peer->p_hdr.info.runtime.pir_prodname)
400                        fd_log_debug("\t['%s' %u]", peer->p_hdr.info.runtime.pir_prodname, peer->p_hdr.info.runtime.pir_firmrev);
401        }
402        fd_log_debug("\n");
403        if (details > FULL) {
404                /* Dump all info */
405                fd_log_debug("\tEntry origin : %s\n", peer->p_dbgorig?: "not set");
406                fd_log_debug("\tConfig flags : %s%s%s%s%s - %s%s%s\n", 
407                                peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_DEFAULT ? "" :
408                                        (peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP ? "IP." : "IPv6."),
409                                peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_DEFAULT ? "" :
410                                        (peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_TCP ? "TCP." : "SCTP."),
411                                peer->p_hdr.info.config.pic_flags.alg ? "PrefTCP." : "",
412                                peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE ? "NoTLSok" :"",
413                                peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD ? "OldTLS" :"",
414                                peer->p_hdr.info.config.pic_flags.exp ? "Expire." : "",
415                                peer->p_hdr.info.config.pic_flags.persist ? "Persist." : ""
416                                );
417                fd_log_debug("\tLifetime : %d sec\n", peer->p_hdr.info.config.pic_lft);
418        }
419}
420
421/* Dump the list of peers */
422void fd_peer_dump_list(int details)
423{
424        struct fd_list * li;
425       
426        fd_log_debug("Dumping list of peers :\n");
427        CHECK_FCT_DO( pthread_rwlock_rdlock(&fd_g_peers_rw), /* continue */ );
428       
429        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
430                struct fd_peer * np = (struct fd_peer *)li->o;
431                fd_peer_dump(np, details);
432        }
433       
434        CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
435}
436
437static struct dict_object *avp_oh_model = NULL;
438static pthread_mutex_t cache_avp_lock = PTHREAD_MUTEX_INITIALIZER;
439
440/* Handle an incoming CER request on a new connection */
441int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx )
442{
443        struct msg * msg;
444        struct avp *avp_oh;
445        struct avp_hdr * avp_hdr;
446        struct fd_list * li, *li_inf;
447        int found = 0;
448        int ret = 0;
449        struct fd_peer * peer;
450        struct cnx_incoming * ev_data;
451       
452        TRACE_ENTRY("%p %p", cer, cnx);
453        CHECK_PARAMS(cer && *cer && cnx && *cnx);
454       
455        msg = *cer; 
456       
457        /* If needed, resolve the dictioanry model for Origin-Host */
458        CHECK_POSIX( pthread_mutex_lock(&cache_avp_lock) );
459        if (!avp_oh_model) {
460                avp_code_t code = AC_ORIGIN_HOST;
461                int ret;
462                CHECK_FCT_DO( ret = fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE, &code, &avp_oh_model, ENOENT),
463                        { CHECK_POSIX( pthread_mutex_unlock(&cache_avp_lock) ); return ret; } );
464        }
465        CHECK_POSIX( pthread_mutex_unlock(&cache_avp_lock) );
466       
467        /* Find the Diameter Identity of the remote peer in the message */
468        CHECK_FCT( fd_msg_search_avp ( msg, avp_oh_model, &avp_oh ) );
469        ASSERT(avp_oh); /* otherwise it should not have passed rules validation, right? */
470        CHECK_FCT( fd_msg_avp_hdr ( avp_oh, &avp_hdr ) );
471       
472        /* First, check if the Origin-Host value  */
473        if (!fd_os_is_valid_DiameterIdentity(avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len)) {
474                TRACE_DEBUG(INFO, "Received new CER with invalid Origin-Host");
475                CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, cer, MSGFL_ANSW_ERROR ) );
476                CHECK_FCT( fd_msg_rescode_set(*cer, "ER_DIAMETER_INVALID_AVP_VALUE", 
477                                                        "Your Origin-Host contains invalid characters.", avp_oh, 1 ) );
478                CHECK_FCT( fd_out_send(cer, *cnx, NULL, FD_CNX_ORDERED) );
479                return EINVAL;
480        }
481       
482        /* 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.
483         * There is space for a small optimization here if needed.
484         */
485        CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_peers_rw) );
486       
487        li_inf = &fd_g_peers;
488        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
489                int cmp, cont;
490                peer = (struct fd_peer *)li->o;
491                cmp = fd_os_almostcasesrch( avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len, peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen, &cont );
492                if (cmp < 0) {
493                        li_inf = li;
494                        continue;
495                }
496                if (cmp == 0) {
497                        found = 1;
498                        break;
499                }
500                if (!cont)
501                        break;
502        }
503       
504        if (!found) {
505                /* Create a new peer entry for this new remote peer */
506                peer = NULL;
507                CHECK_FCT_DO( ret = fd_peer_alloc(&peer), goto out );
508               
509                /* Set the peer Diameter Id and the responder flag parameters */
510                CHECK_MALLOC_DO( peer->p_hdr.info.pi_diamid = os0dup(avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len), 
511                        { ret = ENOMEM; goto out; } );
512                peer->p_hdr.info.pi_diamidlen = avp_hdr->avp_value->os.len;
513                CHECK_MALLOC_DO( peer->p_dbgorig = strdup(fd_cnx_getid(*cnx)), { ret = ENOMEM; goto out; } );
514                peer->p_flags.pf_responder = 1;
515                peer->p_flags.pf_delete = 1;
516               
517                /* Set this peer to expire on inactivity */
518                peer->p_hdr.info.config.pic_flags.exp   = PI_EXP_INACTIVE;
519                peer->p_hdr.info.config.pic_lft         = 3600; /* 1 hour without any message
520                -- RFC3539 states that this must not be inferior to BRINGDOWN_INTERVAL = 5 minutes */
521               
522                /* Insert the new peer in the list (the PSM will take care of setting the expiry after validation) */
523                fd_list_insert_after( li_inf, &peer->p_hdr.chain );
524               
525                /* Start the PSM, which will receive the event bellow */
526                CHECK_FCT_DO( ret = fd_psm_begin(peer), goto out );
527        } else {
528                /* Check if the peer is in zombie state */
529                if (fd_peer_getstate(peer) == STATE_ZOMBIE) {
530                        /* Re-activate the peer */
531                        if (peer->p_hdr.info.config.pic_flags.exp)
532                                peer->p_flags.pf_responder = 1;
533                        CHECK_POSIX_DO( pthread_mutex_lock(&peer->p_state_mtx), );
534                        peer->p_state = STATE_NEW;
535                        CHECK_POSIX_DO( pthread_mutex_unlock(&peer->p_state_mtx), );
536                        peer->p_flags.pf_localterm = 0;
537                        CHECK_FCT_DO( ret = fd_psm_begin(peer), goto out );
538                }
539        }
540       
541        /* Send the new connection event to the PSM */
542        CHECK_MALLOC_DO( ev_data = malloc(sizeof(struct cnx_incoming)), { ret = ENOMEM; goto out; } );
543        memset(ev_data, 0, sizeof(ev_data));
544       
545        ev_data->cer = msg;
546        ev_data->cnx = *cnx;
547        ev_data->validate = !found;
548       
549        CHECK_FCT_DO( ret = fd_event_send(peer->p_events, FDEVP_CNX_INCOMING, sizeof(ev_data), ev_data), goto out );
550       
551out:   
552        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
553
554        if (ret == 0) {
555                /* Reset the "out" parameters, so that they are not cleanup on function return. */
556                *cer = NULL;
557                *cnx = NULL;
558        }
559       
560        return ret;
561}
562
563/* Save a callback to accept / reject incoming unknown peers */
564int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */, int (**cb2)(struct peer_info *)) )
565{
566        struct fd_list * v;
567       
568        TRACE_ENTRY("%p", peer_validate);
569        CHECK_PARAMS(peer_validate);
570       
571        /* Alloc a new entry */
572        CHECK_MALLOC( v = malloc(sizeof(struct fd_list)) );
573        fd_list_init( v, peer_validate );
574       
575        /* Add at the beginning of the list */
576        CHECK_FCT( pthread_rwlock_wrlock(&validators_rw) );
577        fd_list_insert_after(&validators, v);
578        CHECK_FCT( pthread_rwlock_unlock(&validators_rw));
579       
580        /* Done! */
581        return 0;
582}
583
584/* 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) */
585int fd_peer_validate( struct fd_peer * peer )
586{
587        int ret = 0;
588        struct fd_list * v;
589       
590        CHECK_FCT( pthread_rwlock_rdlock(&validators_rw) );
591        for (v = validators.next; v != &validators; v = v->next) {
592                int auth = 0;
593                pthread_cleanup_push(fd_cleanup_rwlock, &validators_rw);
594                CHECK_FCT_DO( ret = ((int(*)(struct peer_info *, int *, int (**)(struct peer_info *)))(v->o)) (&peer->p_hdr.info, &auth, &peer->p_cb2),  );
595                pthread_cleanup_pop(0);
596                if (ret)
597                        goto out;
598                if (auth) {
599                        ret = (auth > 0) ? 0 : -1;
600                        goto out;
601                }
602                peer->p_cb2 = NULL;
603        }
604       
605        /* No callback has given a firm result, the default is to reject */
606        ret = -1;
607out:
608        CHECK_FCT( pthread_rwlock_unlock(&validators_rw));
609        return ret;
610}
Note: See TracBrowser for help on using the repository browser.