Navigation


source: freeDiameter/libfdcore/peers.c @ 691:78b665400097

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

Cleanup all pthread_cleanup_push / pop pairs so that pop is always called after push, or ASSERT(0) is some grave errors

File size: 18.1 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        fd_list_init(&p->p_actives, p);
76        fd_list_init(&p->p_expiry, p);
77        CHECK_FCT( fd_fifo_new(&p->p_tosend) );
78        p->p_hbh = lrand48();
79       
80        fd_list_init(&p->p_sr.srs, p);
81        fd_list_init(&p->p_sr.exp, p);
82        CHECK_POSIX( pthread_mutex_init(&p->p_sr.mtx, NULL) );
83        CHECK_POSIX( pthread_cond_init(&p->p_sr.cnd, NULL) );
84       
85        fd_list_init(&p->p_connparams, p);
86       
87        return 0;
88}
89
90/* Add a new peer entry */
91int fd_peer_add ( struct peer_info * info, char * orig_dbg, void (*cb)(struct peer_info *, void *), void * cb_data )
92{
93        struct fd_peer *p = NULL;
94        struct fd_list * li;
95        int ret = 0;
96        TRACE_ENTRY("%p %p %p %p", info, orig_dbg, cb, cb_data);
97        CHECK_PARAMS(info && info->pi_diamid);
98       
99        /* Create a structure to contain the new peer information */
100        CHECK_FCT( fd_peer_alloc(&p) );
101       
102        /* Copy the informations from the parameters received */
103        CHECK_MALLOC( p->p_hdr.info.pi_diamid = strdup(info->pi_diamid) );
104       
105        memcpy( &p->p_hdr.info.config, &info->config, sizeof(p->p_hdr.info.config) );
106        /* Duplicate the strings if provided */
107        if (info->config.pic_realm) {
108                CHECK_MALLOC( p->p_hdr.info.config.pic_realm = strdup(info->config.pic_realm) );
109        }
110        if (info->config.pic_priority) {
111                CHECK_MALLOC( p->p_hdr.info.config.pic_realm = strdup(info->config.pic_priority) );
112        }
113       
114        /* Move the list of endpoints into the peer */
115        if (info->pi_endpoints.next)
116                while (!FD_IS_LIST_EMPTY( &info->pi_endpoints ) ) {
117                        li = info->pi_endpoints.next;
118                        fd_list_unlink(li);
119                        fd_list_insert_before(&p->p_hdr.info.pi_endpoints, li);
120                }
121       
122        /* The internal data */
123        if (orig_dbg) {
124                CHECK_MALLOC( p->p_dbgorig = strdup(orig_dbg) );
125        } else {
126                CHECK_MALLOC( p->p_dbgorig = strdup("unknown") );
127        }
128        p->p_cb = cb;
129        p->p_cb_data = cb_data;
130       
131        /* Ok, now check if we don't already have an entry with the same Diameter Id, and insert this one */
132        CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_peers_rw) );
133       
134        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
135                struct fd_peer * next = (struct fd_peer *)li;
136                int cmp = strcasecmp( p->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamid );
137                if (cmp > 0)
138                        continue;
139                if (cmp == 0)
140                        ret = EEXIST;
141                break;
142        }
143       
144        /* We can insert the new peer object */
145        if (! ret)
146                do {
147                        /* Update expiry list */
148                        CHECK_FCT_DO( ret = fd_p_expi_update( p ), break );
149
150                        /* Insert the new element in the list */
151                        fd_list_insert_before( li, &p->p_hdr.chain );
152                } while (0);
153
154        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
155        if (ret) {
156                CHECK_FCT( fd_peer_free(&p) );
157        } else {
158                CHECK_FCT( fd_psm_begin(p) );
159        }
160        return ret;
161}
162
163/* Search for a peer */
164int fd_peer_getbyid( char * diamid, struct peer_hdr ** peer )
165{
166        struct fd_list * li;
167       
168        TRACE_ENTRY("%p %p", diamid, peer);
169        CHECK_PARAMS( diamid && peer );
170       
171        *peer = NULL;
172       
173        /* Search in the list */
174        CHECK_POSIX( pthread_rwlock_rdlock(&fd_g_peers_rw) );
175        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
176                struct fd_peer * next = (struct fd_peer *)li;
177                int cmp = strcasecmp( diamid, next->p_hdr.info.pi_diamid );
178                if (cmp > 0)
179                        continue;
180                if (cmp == 0)
181                        *peer = &next->p_hdr;
182                break;
183        }
184        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
185       
186        return 0;
187}
188
189
190#define free_null( _v )         \
191        if (_v) {               \
192                free(_v);       \
193                (_v) = NULL;    \
194        }
195       
196#define free_list( _l )                                                 \
197        while (!FD_IS_LIST_EMPTY(_l)) {                                 \
198                struct fd_list * __li = ((struct fd_list *)(_l))->next; \
199                fd_list_unlink(__li);                                   \
200                free(__li);                                             \
201        }
202
203/* Empty the lists of p_tosend and p_sentreq messages */
204void fd_peer_failover_msg(struct fd_peer * peer)
205{
206        struct msg *m;
207        TRACE_ENTRY("%p", peer);
208        CHECK_PARAMS_DO(CHECK_PEER(peer), return);
209       
210        /* Requeue all messages in the "out" queue */
211        while ( fd_fifo_tryget(peer->p_tosend, &m) == 0 ) {
212                CHECK_FCT_DO(fd_fifo_post(fd_g_outgoing, &m), 
213                        {
214                                /* fallback: destroy the message */
215                                fd_msg_log(FD_MSG_LOG_DROPPED, m, "Internal error: unable to requeue this message during failover process");
216                                CHECK_FCT_DO(fd_msg_free(m), /* What can we do more? */)
217                        } );
218        }
219       
220        /* Requeue all routable sent requests */
221        fd_p_sr_failover(&peer->p_sr);
222       
223        /* Done */
224        return;
225}
226
227/* Destroy a structure once cleanups have been performed (fd_psm_abord, ...) */
228int fd_peer_free(struct fd_peer ** ptr)
229{
230        struct fd_peer *p;
231       
232        TRACE_ENTRY("%p", ptr);
233        CHECK_PARAMS(ptr);
234        p = *ptr;
235        *ptr = NULL;
236        CHECK_PARAMS(p);
237       
238        CHECK_PARAMS( FD_IS_LIST_EMPTY(&p->p_hdr.chain) );
239       
240        free_null(p->p_hdr.info.pi_diamid);
241       
242        free_null(p->p_hdr.info.config.pic_realm); 
243        free_null(p->p_hdr.info.config.pic_priority); 
244       
245        free_null(p->p_hdr.info.runtime.pir_realm);
246        free_null(p->p_hdr.info.runtime.pir_prodname);
247        free_list( &p->p_hdr.info.runtime.pir_apps );
248       
249        free_list( &p->p_hdr.info.pi_endpoints );
250       
251        free_null(p->p_dbgorig);
252       
253        fd_list_unlink(&p->p_expiry);
254        fd_list_unlink(&p->p_actives);
255       
256        CHECK_FCT_DO( fd_fifo_del(&p->p_tosend), /* continue */ );
257        CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_sr.mtx), /* continue */);
258        CHECK_POSIX_DO( pthread_cond_destroy(&p->p_sr.cnd), /* continue */);
259       
260        /* If the callback is still around... */
261        if (p->p_cb)
262                (*p->p_cb)(NULL, p->p_cb_data);
263       
264        /* Free the structure */
265        free(p);
266        return 0;
267}
268
269/* Terminate peer module (destroy all peers, first gently, then violently) */
270int fd_peer_fini()
271{
272        struct fd_list * li;
273        struct fd_list purge = FD_LIST_INITIALIZER(purge); /* Store zombie peers here */
274        int list_empty;
275        struct timespec wait_until, now;
276       
277        TRACE_ENTRY();
278       
279        CHECK_FCT_DO(fd_p_expi_fini(), /* continue */);
280       
281        TRACE_DEBUG(INFO, "Sending terminate signal to all peer connections");
282       
283        CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
284        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
285                struct fd_peer * peer = (struct fd_peer *)li;
286               
287                fd_cpu_flush_cache();
288                if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) {
289                        CHECK_FCT_DO( fd_psm_terminate(peer, "REBOOTING"), /* continue */ );
290                } else {
291                        li = li->prev; /* to avoid breaking the loop */
292                        fd_list_unlink(&peer->p_hdr.chain);
293                        fd_list_insert_before(&purge, &peer->p_hdr.chain);
294                }
295        }
296        list_empty = FD_IS_LIST_EMPTY(&fd_g_peers);
297        CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
298       
299        if (!list_empty) {
300                CHECK_SYS(  clock_gettime(CLOCK_REALTIME, &now)  );
301                TRACE_DEBUG(INFO, "Waiting for connections shutdown... (%d sec max)", DPR_TIMEOUT + 1);
302                wait_until.tv_sec  = now.tv_sec + DPR_TIMEOUT + 1;
303                wait_until.tv_nsec = now.tv_nsec;
304        }
305       
306        while ((!list_empty) && (TS_IS_INFERIOR(&now, &wait_until))) {
307               
308                /* Allow the PSM(s) to execute */
309                sched_yield();
310               
311                /* Remove zombie peers */
312                CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
313                for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
314                        struct fd_peer * peer = (struct fd_peer *)li;
315                        fd_cpu_flush_cache();
316                        if (peer->p_hdr.info.runtime.pir_state == STATE_ZOMBIE) {
317                                li = li->prev; /* to avoid breaking the loop */
318                                fd_list_unlink(&peer->p_hdr.chain);
319                                fd_list_insert_before(&purge, &peer->p_hdr.chain);
320                        }
321                }
322                list_empty = FD_IS_LIST_EMPTY(&fd_g_peers);
323                CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
324                CHECK_SYS(  clock_gettime(CLOCK_REALTIME, &now)  );
325        }
326       
327        if (!list_empty) {
328                TRACE_DEBUG(INFO, "Forcing connections shutdown");
329                CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
330                while (!FD_IS_LIST_EMPTY(&fd_g_peers)) {
331                        struct fd_peer * peer = (struct fd_peer *)(fd_g_peers.next);
332                        fd_psm_abord(peer);
333                        fd_list_unlink(&peer->p_hdr.chain);
334                        fd_list_insert_before(&purge, &peer->p_hdr.chain);
335                }
336                CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
337        }
338       
339        /* Free memory objects of all peers */
340        while (!FD_IS_LIST_EMPTY(&purge)) {
341                struct fd_peer * peer = (struct fd_peer *)(purge.next);
342                fd_list_unlink(&peer->p_hdr.chain);
343                fd_peer_free(&peer);
344        }
345       
346        /* Now empty the validators list */
347        CHECK_FCT_DO( pthread_rwlock_wrlock(&validators_rw), /* continue */ );
348        while (!FD_IS_LIST_EMPTY( &validators )) {
349                struct fd_list * v = validators.next;
350                fd_list_unlink(v);
351                free(v);
352        }
353        CHECK_FCT_DO( pthread_rwlock_unlock(&validators_rw), /* continue */ );
354       
355        return 0;
356}
357
358/* Dump info of one peer */
359void fd_peer_dump(struct fd_peer * peer, int details)
360{
361        if (peer->p_eyec != EYEC_PEER) {
362                fd_log_debug("  Invalid peer @ %p !\n", peer);
363                return;
364        }
365
366        fd_log_debug(">  %s\t%s", STATE_STR(peer->p_hdr.info.runtime.pir_state), peer->p_hdr.info.pi_diamid);
367        if (details > INFO) {
368                fd_log_debug("\t(rlm:%s)", peer->p_hdr.info.runtime.pir_realm ?: "(unknown)");
369                if (peer->p_hdr.info.runtime.pir_prodname)
370                        fd_log_debug("\t['%s' %u]", peer->p_hdr.info.runtime.pir_prodname, peer->p_hdr.info.runtime.pir_firmrev);
371        }
372        fd_log_debug("\n");
373        if (details > FULL) {
374                /* Dump all info */
375                fd_log_debug("\tEntry origin : %s\n", peer->p_dbgorig?: "not set");
376                fd_log_debug("\tConfig flags : %s%s%s%s%s - %s%s%s\n", 
377                                peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_DEFAULT ? "" :
378                                        (peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP ? "IP." : "IPv6."),
379                                peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_DEFAULT ? "" :
380                                        (peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_TCP ? "TCP." : "SCTP."),
381                                peer->p_hdr.info.config.pic_flags.alg ? "PrefTCP." : "",
382                                peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE ? "NoTLSok" :"",
383                                peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD ? "OldTLS" :"",
384                                peer->p_hdr.info.config.pic_flags.exp ? "Expire." : "",
385                                peer->p_hdr.info.config.pic_flags.persist ? "Persist." : ""
386                                );
387                fd_log_debug("\tLifetime : %d sec\n", peer->p_hdr.info.config.pic_lft);
388        }
389}
390
391/* Dump the list of peers */
392void fd_peer_dump_list(int details)
393{
394        struct fd_list * li;
395       
396        fd_log_debug("Dumping list of peers :\n");
397        CHECK_FCT_DO( pthread_rwlock_rdlock(&fd_g_peers_rw), /* continue */ );
398       
399        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
400                struct fd_peer * np = (struct fd_peer *)li;
401                fd_peer_dump(np, details);
402        }
403       
404        CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
405}
406
407/* Handle an incoming CER request on a new connection */
408int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx )
409{
410        struct msg * msg;
411        struct dict_object *avp_oh_model;
412        avp_code_t code = AC_ORIGIN_HOST;
413        struct avp *avp_oh;
414        struct avp_hdr * avp_hdr;
415        struct fd_list * li;
416        int found = 0;
417        int ret = 0;
418        struct fd_peer * peer;
419        struct cnx_incoming * ev_data;
420       
421        TRACE_ENTRY("%p %p", cer, cnx);
422        CHECK_PARAMS(cer && *cer && cnx && *cnx);
423       
424        msg = *cer; 
425       
426        /* Find the Diameter Identity of the remote peer in the message */
427        CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE, &code, &avp_oh_model, ENOENT) );
428        CHECK_FCT( fd_msg_search_avp ( msg, avp_oh_model, &avp_oh ) );
429        CHECK_FCT( fd_msg_avp_hdr ( avp_oh, &avp_hdr ) );
430       
431        /* 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.
432         * There is space for a small optimization here if needed.
433         */
434        CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_peers_rw) );
435       
436        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
437                peer = (struct fd_peer *)li;
438                /* It is probably unwise to use strcasecmp on UTF8 data... To be improved! */
439                int cmp = strncasecmp( (char *)avp_hdr->avp_value->os.data, peer->p_hdr.info.pi_diamid, avp_hdr->avp_value->os.len );
440                if (cmp > 0)
441                        continue;
442                if (cmp == 0)
443                        found = 1;
444                break;
445        }
446       
447        if (!found) {
448                /* Create a new peer entry for this new remote peer */
449                peer = NULL;
450                CHECK_FCT_DO( ret = fd_peer_alloc(&peer), goto out );
451               
452                /* Set the peer Diameter Id and the responder flag parameters */
453                CHECK_MALLOC_DO( peer->p_hdr.info.pi_diamid = malloc(avp_hdr->avp_value->os.len + 1), { ret = ENOMEM; goto out; } );
454                memcpy(peer->p_hdr.info.pi_diamid, avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len);
455                peer->p_hdr.info.pi_diamid[avp_hdr->avp_value->os.len] = '\0';
456                CHECK_MALLOC_DO( peer->p_dbgorig = strdup(fd_cnx_getid(*cnx)), { ret = ENOMEM; goto out; } );
457                peer->p_flags.pf_responder = 1;
458                peer->p_flags.pf_delete = 1;
459               
460                /* Set this peer to expire on inactivity */
461                peer->p_hdr.info.config.pic_flags.exp   = PI_EXP_INACTIVE;
462                peer->p_hdr.info.config.pic_lft         = 3600; /* 1 hour without any message
463                -- RFC3539 states that this must not be inferior to BRINGDOWN_INTERVAL = 5 minutes */
464               
465                /* Insert the new peer in the list (the PSM will take care of setting the expiry after validation) */
466                fd_list_insert_before( li, &peer->p_hdr.chain );
467               
468                /* Start the PSM, which will receive the event bellow */
469                CHECK_FCT_DO( ret = fd_psm_begin(peer), goto out );
470        } else {
471                /* Check if the peer is in zombie state */
472                fd_cpu_flush_cache();
473                if (peer->p_hdr.info.runtime.pir_state == STATE_ZOMBIE) {
474                        /* Re-activate the peer */
475                        if (peer->p_hdr.info.config.pic_flags.exp)
476                                peer->p_flags.pf_responder = 1;
477                        peer->p_hdr.info.runtime.pir_state = STATE_NEW;
478                        CHECK_FCT_DO( ret = fd_psm_begin(peer), goto out );
479                }
480        }
481               
482        /* Send the new connection event to the PSM */
483        CHECK_MALLOC_DO( ev_data = malloc(sizeof(struct cnx_incoming)), { ret = ENOMEM; goto out; } );
484        memset(ev_data, 0, sizeof(ev_data));
485       
486        ev_data->cer = msg;
487        ev_data->cnx = *cnx;
488        ev_data->validate = !found;
489       
490        CHECK_FCT_DO( ret = fd_event_send(peer->p_events, FDEVP_CNX_INCOMING, sizeof(ev_data), ev_data), goto out );
491       
492out:   
493        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
494
495        if (ret == 0) {
496                /* Reset the "out" parameters, so that they are not cleanup on function return. */
497                *cer = NULL;
498                *cnx = NULL;
499        }
500       
501        return ret;
502}
503
504/* Save a callback to accept / reject incoming unknown peers */
505int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */, int (**cb2)(struct peer_info *)) )
506{
507        struct fd_list * v;
508       
509        TRACE_ENTRY("%p", peer_validate);
510        CHECK_PARAMS(peer_validate);
511       
512        /* Alloc a new entry */
513        CHECK_MALLOC( v = malloc(sizeof(struct fd_list)) );
514        fd_list_init( v, peer_validate );
515       
516        /* Add at the beginning of the list */
517        CHECK_FCT( pthread_rwlock_wrlock(&validators_rw) );
518        fd_list_insert_after(&validators, v);
519        CHECK_FCT( pthread_rwlock_unlock(&validators_rw));
520       
521        /* Done! */
522        return 0;
523}
524
525/* 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) */
526int fd_peer_validate( struct fd_peer * peer )
527{
528        int ret = 0;
529        struct fd_list * v;
530       
531        CHECK_FCT( pthread_rwlock_rdlock(&validators_rw) );
532        for (v = validators.next; v != &validators; v = v->next) {
533                int auth = 0;
534                pthread_cleanup_push(fd_cleanup_rwlock, &validators_rw);
535                CHECK_FCT_DO( ret = ((int(*)(struct peer_info *, int *, int (**)(struct peer_info *)))(v->o)) (&peer->p_hdr.info, &auth, &peer->p_cb2),  );
536                pthread_cleanup_pop(0);
537                if (ret)
538                        goto out;
539                if (auth) {
540                        ret = (auth > 0) ? 0 : -1;
541                        goto out;
542                }
543                peer->p_cb2 = NULL;
544        }
545       
546        /* No callback has given a firm result, the default is to reject */
547        ret = -1;
548out:
549        CHECK_FCT( pthread_rwlock_unlock(&validators_rw));
550        return ret;
551}
Note: See TracBrowser for help on using the repository browser.