Navigation


Changeset 13:ef9ef3bf4752 in freeDiameter


Ignore:
Timestamp:
Sep 30, 2009, 6:25:46 PM (15 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Progress on peer state machine

Files:
2 added
11 edited

Legend:

Unmodified
Added
Removed
  • doc/freediameter.conf.sample

    r12 r13  
    163163LoadExtension = "extensions/dict_eap.fdx";
    164164ConnectPeer = "jules.nautilus6.org" ;
     165ConnectPeer = "aaa.nautilus6.org" { No_TLS; No_IP; No_TCP; SCTP_streams = 60; } ;
  • freeDiameter/CMakeLists.txt

    r11 r13  
    1515        dict_base_proto.c
    1616        messages.c
     17        queues.c
    1718        peers.c
    18         queues.c
     19        p_expiry.c
     20        p_psm.c
    1921        )
    2022
  • freeDiameter/fD.h

    r12 r13  
    127127        struct cnxctx   *p_cnxctx;
    128128       
     129        /* Callback on initial connection success / failure */
     130        void            (*p_cb)(struct peer_info *, void *);
     131        void            *p_cb_data;
     132       
    129133};
    130134#define CHECK_PEER( _p ) \
     
    151155/* Functions */
    152156int fd_peer_init();
     157int fd_peer_fini();
    153158void fd_peer_dump_list(int details);
    154 int fd_peer_start();
    155 int fd_peer_waitstart();
     159/* fd_peer_add declared in freeDiameter.h */
     160int fd_peer_rc_decr(struct fd_peer **ptr, int locked);
    156161
     162/* Peer expiry */
     163int fd_p_expi_init(void);
     164int fd_p_expi_fini(void);
     165int fd_p_expi_update(struct fd_peer * peer, int locked );
     166int fd_p_expi_unlink(struct fd_peer * peer, int locked );
    157167
     168/* Peer state machine */
     169int fd_psm_start();
     170int fd_psm_begin(struct fd_peer * peer );
     171int fd_psm_terminate(struct fd_peer * peer );
     172void fd_psm_abord(struct fd_peer * peer );
    158173
    159174#endif /* _FD_H */
  • freeDiameter/fdd.y

    r12 r13  
    210210                                memset(ep, 0, sizeof(struct fd_endpoint));
    211211                                fd_list_init(&ep->chain, NULL);
     212                                ep->meta.conf = 1;
    212213                               
    213214                                memset(&hints, 0, sizeof(hints));
    214215                                hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
    215216                                ret = getaddrinfo($3, NULL, &hints, &ai);
    216                                 if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }
    217                                
     217                                if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); free(ep); YYERROR; }
     218                                ASSERT( ai->ai_addrlen <= sizeof(sSS) );
    218219                                memcpy(&ep->ss, ai->ai_addr, ai->ai_addrlen);
    219220                                free($3);
     
    426427                                memset(ep, 0, sizeof(struct fd_endpoint));
    427428                                fd_list_init(&ep->chain, NULL);
    428                                
     429                                ep->meta.conf = 1;
    429430                                memset(&hints, 0, sizeof(hints));
    430                                 hints.ai_flags = AI_ADDRCONFIG;
     431                                hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
    431432                                ret = getaddrinfo($4, NULL, &hints, &ai);
    432                                 if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }
     433                                if (ret == EAI_NONAME) {
     434                                        /* The name was maybe not numeric, try again */
     435                                        ep->meta.disc = 1;
     436                                        hints.ai_flags &= ~ AI_NUMERICHOST;
     437                                        ret = getaddrinfo($4, NULL, &hints, &ai);
     438                                }
     439                                if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); free(ep); YYERROR; }
    433440                               
    434441                                memcpy(&ep->ss, ai->ai_addr, ai->ai_addrlen);
  • freeDiameter/main.c

    r12 r13  
    8989       
    9090        /* Start the peer state machines */
    91         CHECK_FCT( fd_peer_start() );
     91        CHECK_FCT( fd_psm_start() );
    9292       
    9393        /* Now, just wait for events */
  • freeDiameter/peers.c

    r12 r13  
    5151pthread_rwlock_t fd_g_peers_rw;
    5252
    53 static int started = 0;
    54 static pthread_mutex_t  started_mtx = PTHREAD_MUTEX_INITIALIZER;
    55 static pthread_cond_t   started_cnd = PTHREAD_COND_INITIALIZER;
    56 
    57 /* Wait for start signal */
    58 int fd_peer_waitstart()
    59 {
    60         CHECK_POSIX( pthread_mutex_lock(&started_mtx) );
    61 awake: 
    62         if (! started) {
    63                 pthread_cleanup_push( fd_cleanup_mutex, &started_mtx );
    64                 CHECK_POSIX( pthread_cond_wait(&started_cnd, &started_mtx) );
    65                 pthread_cleanup_pop( 0 );
    66                 goto awake;
    67         }
    68         CHECK_POSIX( pthread_mutex_unlock(&started_mtx) );
    69         return 0;
    70 }
    71 
    72 /* Allow the state machines to start */
    73 int fd_peer_start()
    74 {
    75         CHECK_POSIX( pthread_mutex_lock(&started_mtx) );
    76         started = 1;
    77         CHECK_POSIX( pthread_cond_broadcast(&started_cnd) );
    78         CHECK_POSIX( pthread_mutex_unlock(&started_mtx) );
    79         return 0;
    80 }
    81 
    8253/* Initialize the peers list */
    8354int fd_peer_init()
     
    8758        fd_list_init(&fd_g_peers, NULL);
    8859        CHECK_POSIX( pthread_rwlock_init(&fd_g_peers_rw, NULL) );
     60       
     61        CHECK_FCT(fd_p_expi_init());
     62       
     63        return 0;
     64}
     65
     66/* Terminate peer module (destroy all peers) */
     67int fd_peer_fini()
     68{
     69        TRACE_ENTRY();
     70       
     71        CHECK_FCT_DO(fd_p_expi_fini(), /* continue */);
     72       
     73        TODO("Complete this function")
    8974       
    9075        return 0;
     
    119104}
    120105
     106/* Alloc / reinit a peer structure. if *ptr is not NULL, it must already point to a valid struct fd_peer. */
     107static int fd_sp_reinit(struct fd_peer ** ptr)
     108{
     109        struct fd_peer *p;
     110       
     111        TRACE_ENTRY("%p", ptr);
     112        CHECK_PARAMS(ptr);
     113       
     114        if (*ptr) {
     115                p = *ptr;
     116        } else {
     117                CHECK_MALLOC( p = malloc(sizeof(struct fd_peer)) );
     118                *ptr = p;
     119        }
     120       
     121        /* Now initialize the content */
     122        memset(p, 0, sizeof(struct fd_peer));
     123       
     124        fd_list_init(&p->p_hdr.chain, p);
     125       
     126        fd_list_init(&p->p_hdr.info.pi_endpoints, NULL);
     127        p->p_hdr.info.pi_state = STATE_DISABLED;
     128        fd_list_init(&p->p_hdr.info.pi_apps, NULL);
     129       
     130        p->p_eyec = EYEC_PEER;
     131        CHECK_POSIX( pthread_mutex_init(&p->p_mtx, NULL) );
     132        fd_list_init(&p->p_expiry, p);
     133        fd_list_init(&p->p_actives, p);
     134        p->p_hbh = lrand48();
     135        CHECK_FCT( fd_fifo_new(&p->p_events) );
     136        CHECK_FCT( fd_fifo_new(&p->p_recv) );
     137        CHECK_FCT( fd_fifo_new(&p->p_tosend) );
     138        fd_list_init(&p->p_sentreq, p);
     139       
     140        return 0;
     141}
     142
     143#define free_null( _v )         \
     144        if (_v) {               \
     145                free(_v);       \
     146                (_v) = NULL;    \
     147        }
     148       
     149#define free_list( _l )                                                 \
     150        while (!FD_IS_LIST_EMPTY(_l)) {                                 \
     151                struct fd_list * __li = ((struct fd_list *)(_l))->next; \
     152                fd_list_unlink(__li);                                   \
     153                free(__li);                                             \
     154        }
     155
     156/* Destroy a structure once all cleanups have been performed */
     157static int fd_sp_destroy(struct fd_peer ** ptr)
     158{
     159        struct fd_peer *p;
     160        void * t;
     161       
     162        TRACE_ENTRY("%p", ptr);
     163        CHECK_PARAMS(ptr);
     164        p = *ptr;
     165        *ptr = NULL;
     166        CHECK_PARAMS(p);
     167       
     168        CHECK_PARAMS( (p->p_refcount == 0) && FD_IS_LIST_EMPTY(&p->p_hdr.chain) );
     169       
     170        free_null(p->p_hdr.info.pi_diamid);
     171        free_null(p->p_hdr.info.pi_realm);
     172        free_list( &p->p_hdr.info.pi_endpoints );
     173        /* Assume the security data is already freed */
     174        free_null(p->p_hdr.info.pi_prodname);
     175        free_list( &p->p_hdr.info.pi_apps );
     176       
     177        free_null(p->p_dbgorig);
     178        CHECK_POSIX( pthread_mutex_destroy(&p->p_mtx) );
     179        ASSERT(FD_IS_LIST_EMPTY(&p->p_expiry));
     180        ASSERT(FD_IS_LIST_EMPTY(&p->p_actives));
     181       
     182        CHECK_FCT( fd_thr_term(&p->p_psm) );
     183        while ( fd_fifo_tryget(p->p_events, &t) == 0 ) {
     184                struct fd_event * ev = t;
     185                TRACE_DEBUG(FULL, "Found event %d(%p) in queue of peer %p being destroyed", ev->code, ev->data, p);
     186                free(ev);
     187        }
     188        CHECK_FCT( fd_fifo_del(&p->p_events) );
     189       
     190        CHECK_FCT( fd_thr_term(&p->p_inthr) );
     191        while ( fd_fifo_tryget(p->p_recv, &t) == 0 ) {
     192                struct msg * m = t;
     193                TRACE_DEBUG(FULL, "Found message %p in incoming queue of peer %p being destroyed", m, p);
     194                /* We simply destroy, the remote peer will re-send to someone else...*/
     195                CHECK_FCT(fd_msg_free(m));
     196        }
     197        CHECK_FCT( fd_fifo_del(&p->p_recv) );
     198       
     199        CHECK_FCT( fd_thr_term(&p->p_outthr) );
     200        while ( fd_fifo_tryget(p->p_tosend, &t) == 0 ) {
     201                struct msg * m = t;
     202                TRACE_DEBUG(FULL, "Found message %p in outgoing queue of peer %p being destroyed, requeue", m, p);
     203                /* We simply requeue in global, the routing thread will re-handle it. */
     204               
     205        }
     206        CHECK_FCT( fd_fifo_del(&p->p_tosend) );
     207       
     208        while (!FD_IS_LIST_EMPTY(&p->p_sentreq)) {
     209                struct sentreq * sr = (struct sentreq *)(p->p_sentreq.next);
     210                fd_list_unlink(&sr->chain);
     211                TRACE_DEBUG(FULL, "Found message %p in list of sent requests to peer %p being destroyed, requeue (fallback)", sr->req, p);
     212                CHECK_FCT(fd_fifo_post(fd_g_outgoing, &sr->req));
     213                free(sr);
     214        }
     215       
     216        TRACE_DEBUG(NONE, "TODO: destroy p->p_cnxctx here");
     217       
     218        if (p->p_cb)
     219                (*p->p_cb)(NULL, p->p_cb_data);
     220       
     221        free(p);
     222       
     223        return 0;
     224}
     225
     226/* Decrement refcount, delete if 0 */
     227int fd_peer_rc_decr(struct fd_peer **ptr, int locked)
     228{
     229        int count;
     230        struct fd_peer *p;
     231        TRACE_ENTRY("%p %d", p, locked);
     232       
     233        CHECK_PARAMS(ptr && CHECK_PEER( *ptr ));
     234        p = *ptr;
     235       
     236        if (!locked) {
     237                CHECK_POSIX( pthread_rwlock_rdlock(&fd_g_peers_rw) );
     238                CHECK_POSIX( pthread_mutex_lock( &p->p_mtx ) );
     239                CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
     240        }
     241       
     242        count = --(p->p_refcount);
     243       
     244        if (!locked) {
     245                CHECK_POSIX( pthread_mutex_unlock( &p->p_mtx ) );
     246        }
     247       
     248        if (count <= 0) {
     249                /* All links have already been removed, we can destroy */
     250                CHECK_FCT( fd_sp_destroy(ptr) );
     251        }
     252        return 0;
     253}
     254
    121255/* Add a new peer entry */
    122256int fd_peer_add ( struct peer_info * info, char * orig_dbg, void (*cb)(struct peer_info *, void *), void * cb_data )
    123257{
    124         return ENOTSUP;
    125 }
     258        struct fd_peer *p = NULL;
     259        struct fd_list * li;
     260        int ret = 0;
     261        TRACE_ENTRY("%p %p %p %p", info, orig_dbg, cb, cb_data);
     262        CHECK_PARAMS(info && info->pi_diamid);
     263       
     264        /* Create a structure to contain the new peer information */
     265        CHECK_FCT( fd_sp_reinit(&p) );
     266       
     267        /* Copy the informations from the parameters received */
     268        CHECK_MALLOC( p->p_hdr.info.pi_diamid = strdup(info->pi_diamid) );
     269        if (info->pi_realm) {
     270                CHECK_MALLOC( p->p_hdr.info.pi_realm = strdup(info->pi_realm) );
     271        }
     272       
     273        p->p_hdr.info.pi_flags.pro3 = info->pi_flags.pro3;
     274        p->p_hdr.info.pi_flags.pro4 = info->pi_flags.pro4;
     275        p->p_hdr.info.pi_flags.alg  = info->pi_flags.alg;
     276        p->p_hdr.info.pi_flags.sec  = info->pi_flags.sec;
     277        p->p_hdr.info.pi_flags.exp  = info->pi_flags.exp;
     278       
     279        p->p_hdr.info.pi_lft     = info->pi_lft;
     280        p->p_hdr.info.pi_streams = info->pi_streams;
     281        p->p_hdr.info.pi_port    = info->pi_port;
     282        p->p_hdr.info.pi_tctimer = info->pi_tctimer;
     283        p->p_hdr.info.pi_twtimer = info->pi_twtimer;
     284       
     285        /* Move the items from one list to the other */
     286        while (!FD_IS_LIST_EMPTY( &info->pi_endpoints ) ) {
     287                li = info->pi_endpoints.next;
     288                fd_list_unlink(li);
     289                fd_list_insert_before(&p->p_hdr.info.pi_endpoints, li);
     290        }
     291       
     292        p->p_hdr.info.pi_sec_module = info->pi_sec_module;
     293        memcpy(&p->p_hdr.info.pi_sec_data, &info->pi_sec_data, sizeof(info->pi_sec_data));
     294       
     295        /* The internal data */
     296        if (orig_dbg) {
     297                CHECK_MALLOC( p->p_dbgorig = strdup(orig_dbg) );
     298        } else {
     299                CHECK_MALLOC( p->p_dbgorig = strdup("unknown") );
     300        }
     301        p->p_cb = cb;
     302        p->p_cb_data = cb_data;
     303       
     304        /* Ok, now check if we don't already have an entry with the same Diameter Id, and insert this one */
     305        CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_peers_rw) );
     306        CHECK_POSIX( pthread_mutex_lock( &p->p_mtx ) );
     307       
     308        for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
     309                struct fd_peer * prev = (struct fd_peer *)li;
     310                int cmp = strcasecmp( p->p_hdr.info.pi_diamid, prev->p_hdr.info.pi_diamid );
     311                if (cmp < 0)
     312                        continue;
     313                if (cmp == 0)
     314                        ret = EEXIST;
     315                break;
     316        }
     317       
     318        /* We can insert the new peer object */
     319        if (! ret) {
     320                /* Update expiry list */
     321                CHECK_FCT_DO( ret = fd_p_expi_update( p, 1 ), goto out );
     322               
     323                /* Insert the new element in the list */
     324                fd_list_insert_before( li, &p->p_hdr.chain );
     325                p->p_refcount++;
     326        }
     327
     328out:   
     329        CHECK_POSIX( pthread_mutex_unlock( &p->p_mtx ) );
     330        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
     331        if (ret) {
     332                CHECK_FCT( fd_sp_destroy(&p) );
     333        } else {
     334                CHECK_FCT( fd_psm_start(p) );
     335        }
     336        return ret;
     337}
  • freeDiameter/queues.c

    r10 r13  
    5757       
    5858        /* Stop the providing threads */
     59        TODO("Stop the providing threads");
     60       
    5961        /* Empty all contents */
     62        TODO("Empty all contents (dump to log file ?)");
     63       
    6064        /* Now, delete the queues */
    6165        CHECK_FCT( fd_fifo_del ( &fd_g_incoming ) );
    6266        CHECK_FCT( fd_fifo_del ( &fd_g_outgoing ) );
    6367        CHECK_FCT( fd_fifo_del ( &fd_g_local ) );
     68       
    6469        return 0;
    6570}
  • include/freeDiameter/CMakeLists.txt

    r8 r13  
    1111# Disable SCTP support completly ?
    1212OPTION(DISABLE_SCTP "Disable SCTP support?")
     13
     14# Disable SCTP support completly ?
     15OPTION(ERRORS_ON_TODO "(development) Generate compilation errors on TODO items ?" OFF)
    1316
    1417
  • include/freeDiameter/freeDiameter-host.h.in

    r9 r13  
    4545
    4646#cmakedefine DISABLE_SCTP
    47 
     47#cmakedefine ERRORS_ON_TODO
    4848#cmakedefine DEBUG
    4949
  • include/freeDiameter/freeDiameter.h

    r12 r13  
    8181        struct fd_list  chain;  /* link in cnf_endpoints list */
    8282        sSS             ss;     /* the socket information. */
     83        struct {
     84                unsigned conf : 1; /* This endpoint is statically configured in a configuration file */
     85                unsigned disc : 1; /* This endpoint was resolved from the Diameter Identity or other DNS query */
     86                unsigned adv  : 1; /* This endpoint was advertized in Diameter CER/CEA exchange */
     87                unsigned ll   : 1; /* Lower layer mechanism provided this endpoint */
     88               
     89                /* To add: a validity timestamp for DNS records ? How do we retrieve this lifetime from DNS ? */
     90
     91        }               meta;   /* Additional information about the endpoint */
    8392};
    8493
     
    164173        peer_state_str[ ((unsigned)(state)) <= STATE_REOPEN ? ((unsigned)(state)) : 0 ]
    165174
    166 /* Information about a remote peer, used both for query and for creating a new entry */
     175/* Information about a remote peer. Same structure is used for creating a new entry, but not all fields are meaningful in that case */
    167176struct peer_info {
    168177       
    169         char * pi_diamid;       /* UTF-8, \0 terminated. The Diameter Identity of the remote peer */
    170         char * pi_realm;        /* idem, its realm. */
     178        char *          pi_diamid;      /* UTF-8, \0 terminated. The Diameter Identity of the remote peer */
     179        char *          pi_realm;       /* Its realm, as received in CER/CEA exchange. */
    171180       
    172181        struct {
     
    191200               
    192201                #define PI_EXP_NONE     0       /* the peer entry does not expire */
    193                 #define PI_EXP_INACTIVE 1       /* the peer entry expires after pi_lft seconds without activity */
     202                #define PI_EXP_INACTIVE 1       /* the peer entry expires (i.e. is deleted) after pi_lft seconds without activity */
    194203                unsigned        exp :1;
    195204               
     
    199208                unsigned        inband :2;      /* This is only meaningful with pi_flags.sec == 3 */
    200209               
    201                 unsigned        relay :1;       /* The remote peer advertized the relay application */         
    202         } pi_flags;
     210                unsigned        relay :1;       /* The remote peer advertized the relay application */
     211
     212        }               pi_flags;       /* Some flags */
    203213       
    204214        /* Additional parameters */
    205         uint32_t        pi_lft;         /* lifetime of entry without activity (except watchdogs) (see pi_flags.exp definition) */
     215        uint32_t        pi_lft;         /* lifetime of this peer when inactive (see pi_flags.exp definition) */
    206216        uint16_t        pi_streams;     /* number of streams for SCTP. 0 = default */
    207217        uint16_t        pi_port;        /* port to connect to. 0: default. */
     
    209219        int             pi_twtimer;     /* use this value for TwTimer instead of global, if != 0 */
    210220       
    211         struct fd_list  pi_endpoints;   /* Endpoint(s) of the remote peer (discovered or advertized). list of struct fd_endpoint. DNS resolved if empty. */
     221        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;
    212239       
    213240        /* The remaining information is read-only, not used for peer creation */
     
    244271 * DESCRIPTION:
    245272 *  Add a peer to the list of peers to which the daemon must maintain a connexion.
    246  * If cb is not null, the callback is called when the connection is in OPEN state or
     273 *
     274 *  The content of info parameter is copied, except for the list of endpoints if
     275 * not empty, which is simply moved into the created object. It means that the list
     276 * items must have been malloc'd, so that they can be freed.
     277 *
     278 *  If cb is not null, the callback is called when the connection is in OPEN state or
    247279 * when an error has occurred. The callback should use the pi_state information to
    248  * determine which one it is.
     280 * determine which one it is. If the first parameter of the called callback is NULL, it
     281 * means that the peer is being destroyed before attempt success / failure.
     282 * cb is called to allow freeing cb_data in  * this case.
     283 *
     284 *  The orig_dbg string is only useful for easing debug, and can be left to NULL.
    249285 *
    250286 * RETURN VALUE:
  • include/freeDiameter/libfreeDiameter.h

    r10 r13  
    189189#define TRACE_DEBUG_ALL( str )  \
    190190        TRACE_DEBUG(CALL, str );
     191
     192/* For development only, to keep track of TODO locations in the code */
     193#ifndef ERRORS_ON_TODO
     194#define TODO( _msg, _args... ) \
     195        TRACE_DEBUG(NONE, _msg , ##_args);
     196#else /* ERRORS_ON_TODO */
     197#define TODO( _msg, _args... ) \
     198        "TODO" = _msg ## _args; /* just a stupid compilation error to spot the todo */
     199#endif /* ERRORS_ON_TODO */
    191200
    192201
Note: See TracChangeset for help on using the changeset viewer.