Navigation


Changeset 16:013ce9851131 in freeDiameter


Ignore:
Timestamp:
Oct 2, 2009, 6:57:06 PM (15 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Started including TLS code

Files:
7 edited

Legend:

Unmodified
Added
Removed
  • freeDiameter/CMakeLists.txt

    r13 r16  
    2727        )
    2828
     29# Require GNU TLS for building the daemon
     30FIND_PACKAGE(GNUTLS REQUIRED)
     31INCLUDE_DIRECTORIES(${GNUTLS_INCLUDE_DIRS})
     32SET(FD_LIBS ${FD_LIBS} ${GNUTLS_LIBRARIES})
    2933
    3034# Building the executable
  • freeDiameter/fD.h

    r14 r16  
    151151/* Events codespace for struct fd_peer->p_events */
    152152enum {
     153        /* Dump all info about this peer in the debug log */
     154         FDEVP_DUMP_ALL = 2000
     155       
    153156        /* request to terminate this peer : disconnect, requeue all messages */
    154          FDEVP_TERMINATE = 2000
    155        
    156         /* Dump all info about this peer in the debug log */
    157         ,FDEVP_DUMP_ALL
     157        ,FDEVP_TERMINATE
    158158       
    159159        /* A message was received in the peer */
     
    164164};
    165165const char * fd_pev_str(int event);
     166#define CHECK_EVENT( _e ) \
     167        (((int)(_e) >= FDEVP_DUMP_ALL) && ((int)(_e) <= FDEVP_PSM_TIMEOUT))
    166168
    167169/* Structure to store a sent request */
     
    174176int fd_peer_fini();
    175177void fd_peer_dump_list(int details);
     178void fd_peer_dump(struct fd_peer * peer, int details);
     179int fd_peer_alloc(struct fd_peer ** ptr);
     180int fd_peer_free(struct fd_peer ** ptr);
    176181/* fd_peer_add declared in freeDiameter.h */
    177182
  • freeDiameter/main.c

    r14 r16  
    3838#include <signal.h>
    3939#include <getopt.h>
     40#include <locale.h>
     41
     42#ifdef GCRY_THREAD_OPTION_PTHREAD_IMPL
     43GCRY_THREAD_OPTION_PTHREAD_IMPL;
     44#endif /* GCRY_THREAD_OPTION_PTHREAD_IMPL */
     45
    4046
    4147/* forward declarations */
     
    6268        /* Initialize the library */
    6369        CHECK_FCT( fd_lib_init() );
     70        TRACE_DEBUG(INFO, "libfreeDiameter initialized.");
    6471       
    6572        /* Name this thread */
     
    7178        /* Parse the command-line */
    7279        CHECK_FCT(  main_cmdline(argc, argv)  );
     80       
     81        /* Initialize gnutls */
     82        CHECK_GNUTLS_DO( gnutls_global_init(), return EINVAL );
     83        if ( ! gnutls_check_version(GNUTLS_VERSION) ) {
     84                fprintf(stderr, "The GNUTLS library is too old; found '%s', need '" GNUTLS_VERSION "'\n", gnutls_check_version(NULL));
     85                return EINVAL;
     86        } else {
     87                TRACE_DEBUG(INFO, "GNUTLS library '%s' initialized.", gnutls_check_version(NULL));
     88        }
    7389       
    7490        /* Allow SIGINT and SIGTERM from this point */
     
    141157       
    142158        CHECK_FCT_DO( fd_thr_term(&sig_th), /* continue */ );
     159       
     160        gnutls_global_deinit();
    143161       
    144162        return ret;
     
    168186        int c;
    169187        int option_index = 0;
     188        char * locale;
    170189       
    171190        struct option long_options[] = {
    172                 { "help",       0, NULL, 'h' },
    173                 { "version",    0, NULL, 'V' },
    174                 { "config",     1, NULL, 'c' },
    175                 { "debug",      0, NULL, 'd' },
    176                 { "quiet",      0, NULL, 'q' },
    177                 { NULL, 0, NULL, 0 }
     191                { "help",       no_argument,            NULL, 'h' },
     192                { "version",    no_argument,            NULL, 'V' },
     193                { "config",     required_argument,      NULL, 'c' },
     194                { "debug",      no_argument,            NULL, 'd' },
     195                { "quiet",      no_argument,            NULL, 'q' },
     196                { "dbglocale",  optional_argument,      NULL, 'l' },
     197                { NULL,         0,                      NULL, 0 }
    178198        };
    179199       
     
    182202        /* Loop on arguments */
    183203        while (1) {
    184                 c = getopt_long (argc, argv, "hVc:dq", long_options, &option_index);
     204                c = getopt_long (argc, argv, "hVc:dql:", long_options, &option_index);
    185205                if (c == -1)
    186206                        break;  /* Exit from the loop.  */
     
    200220                                break;
    201221
     222                        case 'l':       /* Change the locale.  */
     223                                locale = setlocale(LC_ALL, optarg?:"");
     224                                if (locale) {
     225                                        TRACE_DEBUG(INFO, "Locale set to: %s", optarg ?: locale);
     226                                } else {
     227                                        TRACE_DEBUG(INFO, "Unable to set locale (%s)", optarg);
     228                                        return EINVAL;
     229                                }
     230                                break;
     231
    202232                        case 'd':       /* Increase verbosity of debug messages.  */
    203233                                fd_g_debug_lvl++;
     
    210240                        case '?':       /* Invalid option.  */
    211241                                /* `getopt_long' already printed an error message.  */
    212                                 TRACE_DEBUG(INFO, "getopt_long found an invalid character\n");
     242                                TRACE_DEBUG(INFO, "getopt_long found an invalid character");
    213243                                return EINVAL;
    214244
    215245                        default:        /* bug: option not considered.  */
    216                                 TRACE_DEBUG(INFO, "A command-line option is missing in parser: %c\n", c);
     246                                TRACE_DEBUG(INFO, "A command-line option is missing in parser: %c", c);
    217247                                ASSERT(0);
    218248                                return EINVAL;
     
    267297        printf( "\nDebug:\n"
    268298                "  These options are mostly useful for developers\n"
     299                "  -l, --dbglocale        Set the locale for error messages\n"
    269300                "  -d, --debug            Increase verbosity of debug messages\n"
    270301                "  -q, --quiet            Decrease verbosity then remove debug messages\n");
  • freeDiameter/p_expiry.c

    r14 r16  
    3636#include "fD.h"
    3737
     38/* Delay for garbage collection of expired threads, in seconds */
     39#define GC_TIME         60
     40
    3841static pthread_t       exp_thr;
     42static pthread_t       gc_thr;
    3943static struct fd_list  exp_list = FD_LIST_INITIALIZER( exp_list );
    4044static pthread_cond_t  exp_cnd  = PTHREAD_COND_INITIALIZER;
    4145static pthread_mutex_t exp_mtx  = PTHREAD_MUTEX_INITIALIZER;
     46
     47static void * gc_th_fct(void * arg)
     48{
     49        fd_log_threadname ( "Peers/garbage" );
     50        TRACE_ENTRY( "" );
     51       
     52        do {
     53                struct fd_list * li, purge = FD_LIST_INITIALIZER(purge);
     54               
     55                pthread_testcancel();
     56                sleep(GC_TIME);
     57               
     58                /* Now check in the peers list if any peer can be deleted */
     59                CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), goto error );
     60               
     61                for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
     62                        struct fd_peer * peer = (struct fd_peer *)li;
     63                       
     64                        if (peer->p_hdr.info.pi_state != STATE_ZOMBIE)
     65                                continue;
     66                       
     67                        if (peer->p_hdr.info.pi_flags.exp == PI_EXP_NONE)
     68                                continue; /* This peer was not supposed to expire, keep it in the list */
     69                       
     70                        /* Ok, the peer was expired, let's remove it */
     71                        li = li->prev; /* to avoid breaking the loop */
     72                        fd_list_unlink(&peer->p_hdr.chain);
     73                        fd_list_insert_before(&purge, &peer->p_hdr.chain);
     74                }
     75
     76                CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), goto error );
     77               
     78                /* Now delete peers that are in the purge list */
     79                while (!FD_IS_LIST_EMPTY(&purge)) {
     80                        struct fd_peer * peer = (struct fd_peer *)(purge.next);
     81                        fd_list_unlink(&peer->p_hdr.chain);
     82                        TRACE_DEBUG(INFO, "Garbage Collect: delete zombie peer '%s'", peer->p_hdr.info.pi_diamid);
     83                        CHECK_FCT_DO( fd_peer_free(&peer), /* Continue... what else to do ? */ );
     84                }
     85        } while (1);
     86       
     87error:
     88        TRACE_DEBUG(INFO, "An error occurred in peers module! GC thread is terminating...");
     89        ASSERT(0);
     90        CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
     91        return NULL;
     92}
     93
    4294
    4395static void * exp_th_fct(void * arg)
     
    98150        TRACE_ENTRY();
    99151        CHECK_FCT( pthread_create( &exp_thr, NULL, exp_th_fct, NULL ) );
     152        CHECK_FCT( pthread_create( &gc_thr,  NULL, gc_th_fct,  NULL ) );
    100153        return 0;
    101154}
     
    113166       
    114167        CHECK_POSIX( pthread_mutex_unlock(&exp_mtx) );
     168        CHECK_FCT_DO( fd_thr_term(&gc_thr), );
    115169        return 0;
    116170}
  • freeDiameter/p_psm.c

    r14 r16  
    3737
    3838const char *peer_state_str[] = {
    39           "STATE_ZOMBIE"
     39          "STATE_NEW"
    4040        , "STATE_OPEN"
    4141        , "STATE_CLOSED"
     
    4646        , "STATE_SUSPECT"
    4747        , "STATE_REOPEN"
     48        , "STATE_ZOMBIE"
    4849        };
    4950
     
    123124}
    124125
     126/* Wait for the next event in the PSM, or timeout */
    125127static int psm_ev_timedget(struct fd_peer * peer, int *code, void ** data)
    126128{
     
    142144       
    143145        return 0;
    144 }       
    145 
    146 /* The state machine thread */
     146}
     147
     148/* The state machine thread (controler) */
    147149static void * p_psm_th( void * arg )
    148150{
    149151        struct fd_peer * peer = (struct fd_peer *)arg;
    150152        int created_started = started;
     153        int event;
     154        void * ev_data;
    151155       
    152156        CHECK_PARAMS_DO( CHECK_PEER(peer), ASSERT(0) );
     
    161165        }
    162166       
    163         /* Wait that the PSM are authorized to start in the daemon */
    164         CHECK_FCT_DO( fd_psm_waitstart(), goto end );
    165        
    166167        /* The state machine starts in CLOSED state */
    167168        peer->p_hdr.info.pi_state = STATE_CLOSED;
     169       
     170        /* Wait that the PSM are authorized to start in the daemon */
     171        CHECK_FCT_DO( fd_psm_waitstart(), goto psm_end );
    168172       
    169173        /* Initialize the timer */
     
    174178        }
    175179       
    176 psm:
    177         do {
    178                 int event;
    179                 void * ev_data;
    180                
    181                 /* Get next event */
    182                 CHECK_FCT_DO( psm_ev_timedget(peer, &event, &ev_data), goto end );
    183                 TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p)\t'%s'",
    184                                 STATE_STR(peer->p_hdr.info.pi_state),
    185                                 fd_pev_str(event), ev_data,
    186                                 peer->p_hdr.info.pi_diamid);
    187                
    188                 /* Now, the action depends on the current state and the incoming event */
    189                
    190        
    191         } while (1);   
    192        
    193        
    194 end:   
    195         /* set STATE_ZOMBIE */
    196         pthread_cleanup_pop(1);
     180psm_loop:
     181        /* Get next event */
     182        CHECK_FCT_DO( psm_ev_timedget(peer, &event, &ev_data), goto psm_end );
     183        TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p)\t'%s'",
     184                        STATE_STR(peer->p_hdr.info.pi_state),
     185                        fd_pev_str(event), ev_data,
     186                        peer->p_hdr.info.pi_diamid);
     187
     188        /* Now, the action depends on the current state and the incoming event */
     189
     190        /* The following two states are impossible */
     191        ASSERT( peer->p_hdr.info.pi_state != STATE_NEW );
     192        ASSERT( peer->p_hdr.info.pi_state != STATE_ZOMBIE );
     193
     194        /* Purge invalid events */
     195        if (!CHECK_EVENT(event)) {
     196                TRACE_DEBUG(INFO, "Invalid event received in PSM '%s' : %d", peer->p_hdr.info.pi_diamid, event);
     197                goto psm_loop;
     198        }
     199
     200        /* Handle the (easy) debug event now */
     201        if (event == FDEVP_DUMP_ALL) {
     202                fd_peer_dump(peer, ANNOYING);
     203                goto psm_loop;
     204        }
     205
     206        /* Requests to terminate the peer object */
     207        if (event == FDEVP_TERMINATE) {
     208                switch (peer->p_hdr.info.pi_state) {
     209                        case STATE_CLOSING:
     210                        case STATE_WAITCNXACK:
     211                        case STATE_WAITCNXACK_ELEC:
     212                        case STATE_WAITCEA:
     213                        case STATE_SUSPECT:
     214                                /* In these cases, we just cleanup the peer object and terminate now */
     215                                TODO("Cleanup the PSM: terminate connection object, ...");
     216                        case STATE_CLOSED:
     217                                /* Then we just terminate the PSM */
     218                                goto psm_end;
     219                               
     220                        case STATE_OPEN:
     221                        case STATE_REOPEN:
     222                                /* We cannot just close the conenction, we have to send a DPR first */
     223                                TODO("Send DPR, mark the peer as CLOSING");
     224                                goto psm_loop;
     225                }
     226        }
     227       
     228        /* MSG_RECEIVED: fd_p_expi_update(struct fd_peer * peer ) */
     229        /* If timeout or OPEN : call cb if defined */
     230
     231        /* Default action : the handling has not yet been implemented. */
     232        TODO("Missing handler in PSM : '%s'\t<-- '%s'", STATE_STR(peer->p_hdr.info.pi_state), fd_pev_str(event));
     233        if (event == FDEVP_PSM_TIMEOUT) {
     234                /* We have not handled timeout in this state, let's postpone next alert */
     235                psm_next_timeout(peer, 0, 60);
     236        }
     237       
     238        goto psm_loop;
     239       
     240psm_end:
     241        pthread_cleanup_pop(1); /* set STATE_ZOMBIE */
    197242        return NULL;
    198243}       
     
    205250{
    206251        TRACE_ENTRY("%p", peer);
    207         TODO("");
    208         return ENOTSUP;
     252       
     253        /* Check the peer and state are OK */
     254        CHECK_PARAMS( CHECK_PEER(peer) && (peer->p_hdr.info.pi_state == STATE_NEW) );
     255       
     256        /* Create the PSM controler thread */
     257        CHECK_POSIX( pthread_create( &peer->p_psm, NULL, p_psm_th, peer ) );
     258       
     259        /* We're done */
     260        return 0;
    209261}
    210262
     
    214266        TRACE_ENTRY("%p", peer);
    215267        CHECK_PARAMS( CHECK_PEER(peer) );
    216         CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, NULL) );
     268        if (peer->p_hdr.info.pi_state != STATE_ZOMBIE) {
     269                CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, NULL) );
     270        } else {
     271                TRACE_DEBUG(FULL, "Peer '%s' was already terminated", peer->p_hdr.info.pi_diamid);
     272        }
    217273        return 0;
    218274}
     
    225281        TODO("Cancel IN thread");
    226282        TODO("Cancel OUT thread");
    227         TODO("Cleanup the connection");
     283        TODO("Cleanup the peer connection object");
     284        TODO("Cleanup the message queues (requeue)");
    228285        return;
    229286}
  • freeDiameter/peers.c

    r14 r16  
    3636#include "fD.h"
    3737
     38/* Global list of peers */
    3839struct fd_list   fd_g_peers = FD_LIST_INITIALIZER(fd_g_peers);
    3940pthread_rwlock_t fd_g_peers_rw = PTHREAD_RWLOCK_INITIALIZER;
    4041
    41 /* Terminate peer module (destroy all peers) */
    42 int fd_peer_fini()
    43 {
    44         struct fd_list * li;
    45         TRACE_ENTRY();
    46        
    47         CHECK_FCT_DO(fd_p_expi_fini(), /* continue */);
    48        
    49         TRACE_DEBUG(INFO, "Sending signal to terminate to all peer connections");
    50        
    51         CHECK_FCT_DO( pthread_rwlock_rdlock(&fd_g_peers_rw), /* continue */ );
    52         /* For each peer in the list, ... */
    53         for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    54                 struct fd_peer * np = (struct fd_peer *)li;
    55                 CHECK_FCT_DO( fd_psm_terminate(np), /* continue */ );
    56         }
    57         CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
    58        
    59         TODO("Give some time to all PSM, then destroy remaining threads");
    60         /* fd_psm_abord(struct fd_peer * peer ) */
    61        
    62         return 0;
    63 }
    64 
    65 /* Dump the list of peers */
    66 void fd_peer_dump_list(int details)
    67 {
    68         struct fd_list * li;
    69        
    70         fd_log_debug("Dumping list of peers :\n");
    71         CHECK_FCT_DO( pthread_rwlock_rdlock(&fd_g_peers_rw), /* continue */ );
    72        
    73         for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
    74                 struct fd_peer * np = (struct fd_peer *)li;
    75                 if (np->p_eyec != EYEC_PEER) {
    76                         fd_log_debug("  Invalid entry @%p !\n", li);
    77                         continue;
    78                 }
    79                
    80                 fd_log_debug("   %s\t%s", STATE_STR(np->p_hdr.info.pi_state), np->p_hdr.info.pi_diamid);
    81                 if (details > INFO) {
    82                         fd_log_debug("\t(rlm:%s)", np->p_hdr.info.pi_realm);
    83                         if (np->p_hdr.info.pi_prodname)
    84                                 fd_log_debug("\t['%s' %u]", np->p_hdr.info.pi_prodname, np->p_hdr.info.pi_firmrev);
    85                         fd_log_debug("\t(from %s)", np->p_dbgorig);
    86                 }
    87                 fd_log_debug("\n");
    88         }
    89        
    90         CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
    91 }
    9242
    9343/* Alloc / reinit a peer structure. if *ptr is not NULL, it must already point to a valid struct fd_peer. */
    94 static int fd_sp_reinit(struct fd_peer ** ptr)
     44int fd_peer_alloc(struct fd_peer ** ptr)
    9545{
    9646        struct fd_peer *p;
     
    12676}
    12777
    128 #define free_null( _v )         \
    129         if (_v) {               \
    130                 free(_v);       \
    131                 (_v) = NULL;    \
    132         }
    133        
    134 #define free_list( _l )                                                 \
    135         while (!FD_IS_LIST_EMPTY(_l)) {                                 \
    136                 struct fd_list * __li = ((struct fd_list *)(_l))->next; \
    137                 fd_list_unlink(__li);                                   \
    138                 free(__li);                                             \
    139         }
    140 
    141 /* Destroy a structure once all cleanups have been performed */
    142 static int fd_sp_destroy(struct fd_peer ** ptr)
    143 {
    144         struct fd_peer *p;
    145         void * t;
    146        
    147         TRACE_ENTRY("%p", ptr);
    148         CHECK_PARAMS(ptr);
    149         p = *ptr;
    150         *ptr = NULL;
    151         CHECK_PARAMS(p);
    152        
    153         CHECK_PARAMS( FD_IS_LIST_EMPTY(&p->p_hdr.chain) );
    154        
    155         free_null(p->p_hdr.info.pi_diamid);
    156         free_null(p->p_hdr.info.pi_realm);
    157         free_list( &p->p_hdr.info.pi_endpoints );
    158         /* Assume the security data is already freed */
    159         free_null(p->p_hdr.info.pi_prodname);
    160         free_list( &p->p_hdr.info.pi_apps );
    161        
    162         free_null(p->p_dbgorig);
    163         ASSERT(FD_IS_LIST_EMPTY(&p->p_expiry));
    164         ASSERT(FD_IS_LIST_EMPTY(&p->p_actives));
    165        
    166         CHECK_FCT( fd_thr_term(&p->p_psm) );
    167         while ( fd_fifo_tryget(p->p_events, &t) == 0 ) {
    168                 struct fd_event * ev = t;
    169                 TRACE_DEBUG(FULL, "Found event %d(%p) in queue of peer %p being destroyed", ev->code, ev->data, p);
    170                 free(ev);
    171         }
    172         CHECK_FCT( fd_fifo_del(&p->p_events) );
    173        
    174         CHECK_FCT( fd_thr_term(&p->p_inthr) );
    175         while ( fd_fifo_tryget(p->p_recv, &t) == 0 ) {
    176                 struct msg * m = t;
    177                 TRACE_DEBUG(FULL, "Found message %p in incoming queue of peer %p being destroyed", m, p);
    178                 /* We simply destroy, the remote peer will re-send to someone else...*/
    179                 CHECK_FCT(fd_msg_free(m));
    180         }
    181         CHECK_FCT( fd_fifo_del(&p->p_recv) );
    182        
    183         CHECK_FCT( fd_thr_term(&p->p_outthr) );
    184         while ( fd_fifo_tryget(p->p_tosend, &t) == 0 ) {
    185                 struct msg * m = t;
    186                 TRACE_DEBUG(FULL, "Found message %p in outgoing queue of peer %p being destroyed, requeue", m, p);
    187                 /* We simply requeue in global, the routing thread will re-handle it. */
    188                
    189         }
    190         CHECK_FCT( fd_fifo_del(&p->p_tosend) );
    191        
    192         while (!FD_IS_LIST_EMPTY(&p->p_sentreq)) {
    193                 struct sentreq * sr = (struct sentreq *)(p->p_sentreq.next);
    194                 fd_list_unlink(&sr->chain);
    195                 TRACE_DEBUG(FULL, "Found message %p in list of sent requests to peer %p being destroyed, requeue (fallback)", sr->req, p);
    196                 CHECK_FCT(fd_fifo_post(fd_g_outgoing, &sr->req));
    197                 free(sr);
    198         }
    199        
    200         if (p->p_cnxctx) {
    201                 TODO("destroy p->p_cnxctx");
    202         }
    203        
    204         if (p->p_cb)
    205                 (*p->p_cb)(NULL, p->p_cb_data);
    206        
    207         free(p);
    208        
    209         return 0;
    210 }
    211 
    212 
    21378/* Add a new peer entry */
    21479int fd_peer_add ( struct peer_info * info, char * orig_dbg, void (*cb)(struct peer_info *, void *), void * cb_data )
     
    22186       
    22287        /* Create a structure to contain the new peer information */
    223         CHECK_FCT( fd_sp_reinit(&p) );
     88        CHECK_FCT( fd_peer_alloc(&p) );
    22489       
    22590        /* Copy the informations from the parameters received */
     
    248113                        fd_list_insert_before(&p->p_hdr.info.pi_endpoints, li);
    249114                }
    250        
    251         p->p_hdr.info.pi_sec_module = info->pi_sec_module;
    252         memcpy(&p->p_hdr.info.pi_sec_data, &info->pi_sec_data, sizeof(info->pi_sec_data));
    253115       
    254116        /* The internal data */
     
    286148        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
    287149        if (ret) {
    288                 CHECK_FCT( fd_sp_destroy(&p) );
     150                CHECK_FCT( fd_peer_free(&p) );
    289151        } else {
    290152                CHECK_FCT( fd_psm_begin(p) );
     
    292154        return ret;
    293155}
     156
     157
     158#define free_null( _v )         \
     159        if (_v) {               \
     160                free(_v);       \
     161                (_v) = NULL;    \
     162        }
     163       
     164#define free_list( _l )                                                 \
     165        while (!FD_IS_LIST_EMPTY(_l)) {                                 \
     166                struct fd_list * __li = ((struct fd_list *)(_l))->next; \
     167                fd_list_unlink(__li);                                   \
     168                free(__li);                                             \
     169        }
     170
     171/* Destroy a structure once all cleanups have been performed */
     172int fd_peer_free(struct fd_peer ** ptr)
     173{
     174        struct fd_peer *p;
     175        void * t;
     176       
     177        TRACE_ENTRY("%p", ptr);
     178        CHECK_PARAMS(ptr);
     179        p = *ptr;
     180        *ptr = NULL;
     181        CHECK_PARAMS(p);
     182       
     183        CHECK_PARAMS( FD_IS_LIST_EMPTY(&p->p_hdr.chain) );
     184       
     185        free_null(p->p_hdr.info.pi_diamid);
     186        free_null(p->p_hdr.info.pi_realm);
     187        free_list( &p->p_hdr.info.pi_endpoints );
     188        /* Assume the security data is already freed */
     189        free_null(p->p_hdr.info.pi_prodname);
     190        free_list( &p->p_hdr.info.pi_apps );
     191       
     192        free_null(p->p_dbgorig);
     193        ASSERT(FD_IS_LIST_EMPTY(&p->p_expiry));
     194        ASSERT(FD_IS_LIST_EMPTY(&p->p_actives));
     195       
     196        CHECK_FCT( fd_thr_term(&p->p_psm) );
     197        while ( fd_fifo_tryget(p->p_events, &t) == 0 ) {
     198                struct fd_event * ev = t;
     199                TRACE_DEBUG(FULL, "Found event %d(%p) in queue of peer %p being destroyed", ev->code, ev->data, p);
     200                free(ev);
     201        }
     202        CHECK_FCT( fd_fifo_del(&p->p_events) );
     203       
     204        CHECK_FCT( fd_thr_term(&p->p_inthr) );
     205        while ( fd_fifo_tryget(p->p_recv, &t) == 0 ) {
     206                struct msg * m = t;
     207                TRACE_DEBUG(FULL, "Found message %p in incoming queue of peer %p being destroyed", m, p);
     208                /* We simply destroy, the remote peer will re-send to someone else...*/
     209                CHECK_FCT(fd_msg_free(m));
     210        }
     211        CHECK_FCT( fd_fifo_del(&p->p_recv) );
     212       
     213        CHECK_FCT( fd_thr_term(&p->p_outthr) );
     214        while ( fd_fifo_tryget(p->p_tosend, &t) == 0 ) {
     215                struct msg * m = t;
     216                TRACE_DEBUG(FULL, "Found message %p in outgoing queue of peer %p being destroyed, requeue", m, p);
     217                /* We simply requeue in global, the routing thread will re-handle it. */
     218               
     219        }
     220        CHECK_FCT( fd_fifo_del(&p->p_tosend) );
     221       
     222        while (!FD_IS_LIST_EMPTY(&p->p_sentreq)) {
     223                struct sentreq * sr = (struct sentreq *)(p->p_sentreq.next);
     224                fd_list_unlink(&sr->chain);
     225                TRACE_DEBUG(FULL, "Found message %p in list of sent requests to peer %p being destroyed, requeue (fallback)", sr->req, p);
     226                CHECK_FCT(fd_fifo_post(fd_g_outgoing, &sr->req));
     227                free(sr);
     228        }
     229       
     230        if (p->p_cnxctx) {
     231                TODO("destroy p->p_cnxctx");
     232        }
     233       
     234        if (p->p_cb)
     235                (*p->p_cb)(NULL, p->p_cb_data);
     236       
     237        free(p);
     238       
     239        return 0;
     240}
     241
     242/* Terminate peer module (destroy all peers) */
     243int fd_peer_fini()
     244{
     245        struct fd_list * li;
     246        struct fd_list purge = FD_LIST_INITIALIZER(purge); /* Store zombie peers here */
     247        int list_empty;
     248        struct timespec wait_until, now;
     249       
     250        TRACE_ENTRY();
     251       
     252        CHECK_FCT_DO(fd_p_expi_fini(), /* continue */);
     253       
     254        TRACE_DEBUG(INFO, "Sending terminate signal to all peer connections");
     255       
     256        CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
     257        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
     258                struct fd_peer * peer = (struct fd_peer *)li;
     259               
     260                if (peer->p_hdr.info.pi_state != STATE_ZOMBIE) {
     261                        CHECK_FCT_DO( fd_psm_terminate(peer), /* continue */ );
     262                } else {
     263                        li = li->prev; /* to avoid breaking the loop */
     264                        fd_list_unlink(&peer->p_hdr.chain);
     265                        fd_list_insert_before(&purge, &peer->p_hdr.chain);
     266                }
     267        }
     268        list_empty = FD_IS_LIST_EMPTY(&fd_g_peers);
     269        CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
     270       
     271        if (!list_empty) {
     272                CHECK_SYS(  clock_gettime(CLOCK_REALTIME, &now)  );
     273                TRACE_DEBUG(INFO, "Waiting for connections shutdown... (%d sec max)", DPR_TIMEOUT);
     274                wait_until.tv_sec  = now.tv_sec + DPR_TIMEOUT;
     275                wait_until.tv_nsec = now.tv_nsec;
     276        }
     277       
     278        while ((!list_empty) && (TS_IS_INFERIOR(&now, &wait_until))) {
     279               
     280                /* Allow the PSM(s) to execute */
     281                pthread_yield();
     282               
     283                /* Remove zombie peers */
     284                CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
     285                for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
     286                        struct fd_peer * peer = (struct fd_peer *)li;
     287                        if (peer->p_hdr.info.pi_state == STATE_ZOMBIE) {
     288                                li = li->prev; /* to avoid breaking the loop */
     289                                fd_list_unlink(&peer->p_hdr.chain);
     290                                fd_list_insert_before(&purge, &peer->p_hdr.chain);
     291                        }
     292                }
     293                list_empty = FD_IS_LIST_EMPTY(&fd_g_peers);
     294                CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
     295        }
     296       
     297        if (!list_empty) {
     298                TRACE_DEBUG(INFO, "Forcing connections shutdown");
     299                CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ );
     300                while (!FD_IS_LIST_EMPTY(&fd_g_peers)) {
     301                        struct fd_peer * peer = (struct fd_peer *)(fd_g_peers.next);
     302                        fd_psm_abord(peer);
     303                        fd_list_unlink(&peer->p_hdr.chain);
     304                        fd_list_insert_before(&purge, &peer->p_hdr.chain);
     305                }
     306                CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
     307        }
     308       
     309        /* Free memory objects of all peers */
     310        while (!FD_IS_LIST_EMPTY(&purge)) {
     311                struct fd_peer * peer = (struct fd_peer *)(purge.next);
     312                fd_list_unlink(&peer->p_hdr.chain);
     313                fd_peer_free(&peer);
     314        }
     315       
     316        return 0;
     317}
     318
     319/* Dump info of one peer */
     320void fd_peer_dump(struct fd_peer * peer, int details)
     321{
     322        if (peer->p_eyec != EYEC_PEER) {
     323                fd_log_debug("  Invalid peer @ %p !\n", peer);
     324                return;
     325        }
     326
     327        fd_log_debug(">  %s\t%s", STATE_STR(peer->p_hdr.info.pi_state), peer->p_hdr.info.pi_diamid);
     328        if (details > INFO) {
     329                fd_log_debug("\t(rlm:%s)", peer->p_hdr.info.pi_realm);
     330                if (peer->p_hdr.info.pi_prodname)
     331                        fd_log_debug("\t['%s' %u]", peer->p_hdr.info.pi_prodname, peer->p_hdr.info.pi_firmrev);
     332        }
     333        fd_log_debug("\n");
     334        if (details > FULL) {
     335                /* Dump all info */
     336                fd_log_debug("\tEntry origin : %s\n", peer->p_dbgorig);
     337                fd_log_debug("\tFlags : %s%s%s%s%s - %s%s%s\n",
     338                                peer->p_hdr.info.pi_flags.pro3 == PI_P3_DEFAULT ? "" :
     339                                        (peer->p_hdr.info.pi_flags.pro3 == PI_P3_IP ? "IP." : "IPv6."),
     340                                peer->p_hdr.info.pi_flags.pro4 == PI_P4_DEFAULT ? "" :
     341                                        (peer->p_hdr.info.pi_flags.pro4 == PI_P4_TCP ? "TCP." : "SCTP."),
     342                                peer->p_hdr.info.pi_flags.alg ? "PrefTCP." : "",
     343                                peer->p_hdr.info.pi_flags.sec == PI_SEC_DEFAULT ? "" :
     344                                        (peer->p_hdr.info.pi_flags.sec == PI_SEC_NONE ? "IPSec." : "InbandTLS."),
     345                                peer->p_hdr.info.pi_flags.exp ? "Expire." : "",
     346                                peer->p_hdr.info.pi_flags.inband & PI_INB_NONE ? "InbandIPsecOK." : "",
     347                                peer->p_hdr.info.pi_flags.inband & PI_INB_TLS ?  "InbandTLSOK." : "",
     348                                peer->p_hdr.info.pi_flags.relay ? "Relay (0xffffff)" : "No relay"
     349                                );
     350                fd_log_debug("\tLifetime : %d sec\n", peer->p_hdr.info.pi_lft);
     351               
     352                TODO("Dump remaining useful information");
     353        }
     354}
     355
     356/* Dump the list of peers */
     357void fd_peer_dump_list(int details)
     358{
     359        struct fd_list * li;
     360       
     361        fd_log_debug("Dumping list of peers :\n");
     362        CHECK_FCT_DO( pthread_rwlock_rdlock(&fd_g_peers_rw), /* continue */ );
     363       
     364        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
     365                struct fd_peer * np = (struct fd_peer *)li;
     366                fd_peer_dump(np, details);
     367        }
     368       
     369        CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
     370}
     371
  • include/freeDiameter/freeDiameter.h

    r14 r16  
    3939
    4040#include <freeDiameter/libfreeDiameter.h>
     41#include <gnutls/gnutls.h>
     42#include <gnutls/x509.h>
     43
     44/* GNUTLS version */
     45#ifndef GNUTLS_VERSION
     46#define GNUTLS_VERSION LIBGNUTLS_VERSION
     47#endif /* GNUTLS_VERSION */
     48
     49/* Check the return value of a GNUTLS function, log and propagate */
     50#define CHECK_GNUTLS_DO( __call__, __fallback__ ) {                                             \
     51        int __ret__;                                                                            \
     52        TRACE_DEBUG_ALL( "Check FCT: " #__call__ );                                             \
     53        __ret__ = (__call__);                                                                   \
     54        if (__ret__ < 0) {                                                                      \
     55                TRACE_DEBUG(INFO, "Error in '" #__call__ "':\t%s", gnutls_strerror(__ret__));   \
     56                __fallback__;                                                                   \
     57        }                                                                                       \
     58}
    4159
    4260
     
    7088                unsigned tls_alg: 1;    /* TLS algorithm for initiated cnx. 0: separate port. 1: inband-security (old) */
    7189        }                cnf_flags;
     90       
     91        struct {
     92                        /* GNUTLS global state */
     93                        /* Server credential(s) */
     94        }                cnf_sec_data;
    7295       
    7396        uint32_t         cnf_orstateid; /* The value to use in Origin-State-Id, default to random value */
     
    151174enum peer_state {
    152175        /* Stable states */
    153         STATE_ZOMBIE = 0,       /* The threads handling the peer are not running for some reason */
     176        STATE_NEW = 0,          /* The peer has been just been created, PSM thread not started yet */
    154177        STATE_OPEN,             /* Connexion established */
    155178       
     
    168191        STATE_SUSPECT,          /* A DWR was sent and not answered within TwTime. Failover in progress. */
    169192        STATE_REOPEN,           /* Connection has been re-established, waiting for 3 DWR/DWA exchanges before putting back to service */
     193       
     194        /* Error state */
     195        STATE_ZOMBIE            /* The PSM thread is not running anymore; it must be re-started or peer should be deleted. */
     196#define STATE_MAX STATE_ZOMBIE
    170197};
    171198extern const char *peer_state_str[];
    172199#define STATE_STR(state) \
    173         (((unsigned)(state)) <= STATE_REOPEN ? peer_state_str[((unsigned)(state)) ] : "<Invalid>")
     200        (((unsigned)(state)) <= STATE_MAX ? peer_state_str[((unsigned)(state)) ] : "<Invalid>")
    174201
    175202/* Information about a remote peer. Same structure is used for creating a new entry, but not all fields are meaningful in that case */
     
    220247       
    221248        struct fd_list  pi_endpoints;   /* Endpoint(s) of the remote peer (configured, discovered, or advertized). list of struct fd_endpoint. DNS resolved if empty. */
    222        
    223         /* TLS specific data -- the exact data pointed here depends on the security module in use (ex: gnutls, ...) */
    224         enum {
    225                 PI_SEC_GNUTLS = 0,      /* The security module is GNUTLS, this is the default */
    226                 PI_SEC_OTHER            /* Another security module (TBD) */
    227         }               pi_sec_module;
    228         union {
    229                 /* Security data when pi_sec_module == PI_SEC_GNUTLS */
    230                 struct {
    231                         void *  CA;     /* Authority to use to validate this peer credentials (a CA or root certificate) -- use default if NULL */
    232                         void *  cred;   /* The (valid) credentials that the peer has presented */
    233                 }       gnutls;
    234                 /* Security data when pi_sec_module == PI_SEC_OTHER */
    235                 struct {
    236                         void * dummy;   /* Something meaningful for the other security module */
    237                 }       other;
    238         }               pi_sec_data;
    239249       
    240250        /* The remaining information must not be modified, and is not used for peer creation */
     
    245255        uint32_t        pi_firmrev;     /* Content of the Firmware-Revision AVP */
    246256        struct fd_list  pi_apps;        /* applications advertised by the remote peer, except relay (pi_flags.relay) */
     257        struct {
     258                /* This is inspired from http://www.gnu.org/software/gnutls/manual/gnutls.html#ex_003ax509_002dinfo */
     259                const gnutls_datum_t    *cert_list;     /* The (valid) credentials that the peer has presented */
     260                unsigned int             cert_list_size;/* Number of certificates in the list */
     261        }               pi_sec_data;
    247262};
    248263
Note: See TracChangeset for help on using the changeset viewer.