# HG changeset patch # User Sebastien Decugis # Date 1257398926 -32400 # Node ID cc3c59fe98fe481d6999d9aecdd34b4e7a42ff7e # Parent 1498b3c7304c000762fbf538c394b1581fa1eb27 Lot of cleanups in peer structure management diff -r 1498b3c7304c -r cc3c59fe98fe freeDiameter/CMakeLists.txt --- a/freeDiameter/CMakeLists.txt Mon Nov 02 17:31:36 2009 +0900 +++ b/freeDiameter/CMakeLists.txt Thu Nov 05 14:28:46 2009 +0900 @@ -20,6 +20,7 @@ queues.c peers.c p_ce.c + p_cnx.c p_dw.c p_dp.c p_expiry.c diff -r 1498b3c7304c -r cc3c59fe98fe freeDiameter/fD.h --- a/freeDiameter/fD.h Mon Nov 02 17:31:36 2009 +0900 +++ b/freeDiameter/fD.h Thu Nov 05 14:28:46 2009 +0900 @@ -118,15 +118,13 @@ /* Some flags influencing the peer state machine */ struct { - unsigned pf_responder : 1; /* The local peer is responder on the connection */ + unsigned pf_responder : 1; /* The peer has been created to handle incoming connection */ unsigned pf_dw_pending : 1; /* A DWR message was sent and not answered yet */ unsigned pf_cnx_pb : 1; /* The peer was disconnected because of watchdogs; must exchange 3 watchdogs before putting back to normal */ unsigned pf_reopen_cnt : 2; /* remaining DW to be exchanged after re-established connection */ - /* to be completed */ - } p_flags; /* The events queue, peer state machine thread, timer for states timeouts */ @@ -144,6 +142,14 @@ /* Sent requests (for fallback), list of struct sentreq ordered by hbh */ struct sr_list p_sr; + /* Data for transitional states before the peer is in OPEN state */ + struct { + struct cnxctx * p_initiator; /* Connection before CEA is received */ + struct cnxctx * p_receiver; /* Only used in case of election */ + pthread_t p_ini_thr; + }; + + /* connection context: socket and related information */ struct cnxctx *p_cnxctx; @@ -175,9 +181,12 @@ /* Endpoints of a connection have been changed (multihomed SCTP). */ ,FDEVP_CNX_EP_CHANGE - /* A new connection has been established (data contains the appropriate info) */ + /* A new connection (with a CER) has been received */ ,FDEVP_CNX_INCOMING + /* A new connection has been established to the remote peer (event data is the cnxctx object) */ + ,FDEVP_CNX_ESTABLISHED + /* The PSM state is expired */ ,FDEVP_PSM_TIMEOUT @@ -195,6 +204,7 @@ case_str(FDEVP_CNX_ERROR); \ case_str(FDEVP_CNX_EP_CHANGE); \ case_str(FDEVP_CNX_INCOMING); \ + case_str(FDEVP_CNX_ESTABLISHED); \ case_str(FDEVP_PSM_TIMEOUT); \ } \ TRACE_DEBUG(FULL, "Unknown event : %d", event); \ diff -r 1498b3c7304c -r cc3c59fe98fe freeDiameter/fdd.y --- a/freeDiameter/fdd.y Mon Nov 02 17:31:36 2009 +0900 +++ b/freeDiameter/fdd.y Thu Nov 05 14:28:46 2009 +0900 @@ -315,9 +315,8 @@ connpeer: { memset(&fddpi, 0, sizeof(fddpi)); + fddpi.config.pic_flags.persist = PI_PRST_ALWAYS; fd_list_init( &fddpi.pi_endpoints, NULL ); - fd_list_init( &fddpi.pi_apps, NULL ); - fddpi.pi_flags.persist = PI_PRST_ALWAYS; } CONNPEER '=' QSTRING peerinfo ';' { @@ -327,7 +326,8 @@ /* Now destroy any content in the structure */ free(fddpi.pi_diamid); - free(fddpi.pi_sec_data.priority); + free(fddpi.config.pic_realm); + free(fddpi.config.pic_priority); while (!FD_IS_LIST_EMPTY(&fddpi.pi_endpoints)) { struct fd_list * li = fddpi.pi_endpoints.next; fd_list_unlink(li); @@ -343,21 +343,21 @@ peerparams: /* empty */ | peerparams NOIP ';' { - if ((conf->cnf_flags.no_ip6) || (fddpi.pi_flags.pro3 == PI_P3_IP)) { + if ((conf->cnf_flags.no_ip6) || (fddpi.config.pic_flags.pro3 == PI_P3_IP)) { yyerror (&yylloc, conf, "No_IP conflicts with a No_IPv6 directive."); YYERROR; } got_peer_noip++; - fddpi.pi_flags.pro3 = PI_P3_IPv6; + fddpi.config.pic_flags.pro3 = PI_P3_IPv6; } | peerparams NOIP6 ';' { - if ((conf->cnf_flags.no_ip4) || (fddpi.pi_flags.pro3 == PI_P3_IPv6)) { + if ((conf->cnf_flags.no_ip4) || (fddpi.config.pic_flags.pro3 == PI_P3_IPv6)) { yyerror (&yylloc, conf, "No_IPv6 conflicts with a No_IP directive."); YYERROR; } got_peer_noipv6++; - fddpi.pi_flags.pro3 = PI_P3_IP; + fddpi.config.pic_flags.pro3 = PI_P3_IP; } | peerparams NOTCP ';' { @@ -365,59 +365,55 @@ yyerror (&yylloc, conf, "No_TCP cannot be specified in daemon compiled with DISABLE_SCTP option."); YYERROR; #endif - if ((conf->cnf_flags.no_sctp) || (fddpi.pi_flags.pro4 == PI_P4_TCP)) { + if ((conf->cnf_flags.no_sctp) || (fddpi.config.pic_flags.pro4 == PI_P4_TCP)) { yyerror (&yylloc, conf, "No_TCP conflicts with a No_SCTP directive."); YYERROR; } got_peer_notcp++; - fddpi.pi_flags.pro4 = PI_P4_SCTP; + fddpi.config.pic_flags.pro4 = PI_P4_SCTP; } | peerparams NOSCTP ';' { - if ((conf->cnf_flags.no_tcp) || (fddpi.pi_flags.pro4 == PI_P4_SCTP)) { + if ((conf->cnf_flags.no_tcp) || (fddpi.config.pic_flags.pro4 == PI_P4_SCTP)) { yyerror (&yylloc, conf, "No_SCTP conflicts with a No_TCP directive."); YYERROR; } got_peer_nosctp++; - fddpi.pi_flags.pro4 = PI_P4_TCP; + fddpi.config.pic_flags.pro4 = PI_P4_TCP; } | peerparams PREFERTCP ';' { - fddpi.pi_flags.alg = PI_ALGPREF_TCP; + fddpi.config.pic_flags.alg = PI_ALGPREF_TCP; } | peerparams OLDTLS ';' { - if (fddpi.pi_flags.sec == PI_SEC_NONE) { - yyerror (&yylloc, conf, "ConnectPeer: TLS_old_method conflicts with No_TLS."); - YYERROR; - } - fddpi.pi_flags.sec = PI_SEC_TLS_OLD; + fddpi.config.pic_flags.sec |= PI_SEC_TLS_OLD; } | peerparams NOTLS ';' { - if (fddpi.pi_flags.sec == PI_SEC_TLS_OLD) { - yyerror (&yylloc, conf, "ConnectPeer: No_TLS conflicts with TLS_old_method."); - YYERROR; - } - fddpi.pi_flags.sec = PI_SEC_NONE; + fddpi.config.pic_flags.sec |= PI_SEC_NONE; + } + | peerparams REALM '=' QSTRING ';' + { + fddpi.config.pic_realm = $4; } | peerparams PORT '=' INTEGER ';' { CHECK_PARAMS_DO( ($4 > 0) && ($4 < 1<<16), - { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); - fddpi.pi_port = (uint16_t)$4; + { yyerror (&yylloc, conf, "Invalid port value"); YYERROR; } ); + fddpi.config.pic_port = (uint16_t)$4; } | peerparams TCTIMER '=' INTEGER ';' { - fddpi.pi_tctimer = $4; + fddpi.config.pic_tctimer = $4; + } + | peerparams TWTIMER '=' INTEGER ';' + { + fddpi.config.pic_twtimer = $4; } | peerparams TLS_PRIO '=' QSTRING ';' { - fddpi.pi_sec_data.priority = $4; - } - | peerparams TWTIMER '=' INTEGER ';' - { - fddpi.pi_twtimer = $4; + fddpi.config.pic_priority = $4; } | peerparams CONNTO '=' QSTRING ';' { diff -r 1498b3c7304c -r cc3c59fe98fe freeDiameter/p_ce.c --- a/freeDiameter/p_ce.c Mon Nov 02 17:31:36 2009 +0900 +++ b/freeDiameter/p_ce.c Thu Nov 05 14:28:46 2009 +0900 @@ -46,7 +46,7 @@ int fd_p_ce_handle_newCER(struct msg ** msg, struct fd_peer * peer, struct cnxctx ** cnx, int valid) { - switch (peer->p_hdr.info.pi_state) { + switch (peer->p_hdr.info.runtime.pir_state) { case STATE_CLOSED: TODO("Handle the CER, validate the peer if needed (and set expiry), set the alt_fifo in the connection, reply a CEA, eventually handshake, move to OPEN or REOPEN state"); /* In case of error : DIAMETER_UNKNOWN_PEER */ diff -r 1498b3c7304c -r cc3c59fe98fe freeDiameter/p_cnx.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/p_cnx.c Thu Nov 05 14:28:46 2009 +0900 @@ -0,0 +1,84 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "fD.h" + +/* This file contains code used by a peer state machine to initiate a connection to remote peer */ + + +/* The thread that attempts the connection */ +static void * connect_thr(void * arg) +{ + struct fd_peer * peer = arg; + struct cnxctx * cnx = NULL; + + + + /* Use the flags in the peer to select the protocol */ + + TODO("loop on fd_cnx_cli_connect_tcp or fd_cnx_cli_connect_sctp"); + + + /* Now, we have an established connection in cnx */ + + pthread_cleanup_push((void *)fd_cnx_destroy, cnx); + + /* Handshake if needed (secure port) */ + + + + /* Upon success, generate FDEVP_CNX_ESTABLISHED */ + CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ESTABLISHED, 0, cnx), goto fatal_error ); + pthread_cleanup_pop(0); + + return NULL; +fatal_error: + /* Cleanup the connection */ + fd_cnx_destroy(cnx); + + /* Generate a termination event */ + CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); + + return NULL; +} + + +/* Initiate a connection attempt to a remote peer */ +int fd_p_cnx_init(struct fd_peer * peer) +{ + /* Start the connect thread */ + CHECK_FCT( pthread_create(&peer->p_ini_thr, NULL, connect_thr, peer) ); + return 0; +} diff -r 1498b3c7304c -r cc3c59fe98fe freeDiameter/p_expiry.c --- a/freeDiameter/p_expiry.c Mon Nov 02 17:31:36 2009 +0900 +++ b/freeDiameter/p_expiry.c Thu Nov 05 14:28:46 2009 +0900 @@ -60,10 +60,10 @@ for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) { struct fd_peer * peer = (struct fd_peer *)li; - if (peer->p_hdr.info.pi_state != STATE_ZOMBIE) + if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) continue; - if (peer->p_hdr.info.pi_flags.persist == PI_PRST_ALWAYS) + if (peer->p_hdr.info.config.pic_flags.persist == PI_PRST_ALWAYS) continue; /* This peer was not supposed to terminate, keep it in the list for debug */ /* Ok, the peer was expired, let's remove it */ @@ -157,13 +157,12 @@ { CHECK_FCT_DO( fd_thr_term(&exp_thr), ); CHECK_POSIX( pthread_mutex_lock(&exp_mtx) ); - while (!FD_IS_LIST_EMPTY(&exp_list)) { struct fd_peer * peer = (struct fd_peer *)(exp_list.next->o); fd_list_unlink(&peer->p_expiry ); } + CHECK_POSIX( pthread_mutex_unlock(&exp_mtx) ); - CHECK_POSIX( pthread_mutex_unlock(&exp_mtx) ); CHECK_FCT_DO( fd_thr_term(&gc_thr), ); return 0; } @@ -179,12 +178,12 @@ fd_list_unlink(&peer->p_expiry ); /* if peer expires */ - if (peer->p_hdr.info.pi_flags.exp) { + if (peer->p_hdr.info.config.pic_flags.exp) { struct fd_list * li; /* update the p_exp_timer value */ CHECK_SYS( clock_gettime(CLOCK_REALTIME, &peer->p_exp_timer) ); - peer->p_exp_timer.tv_sec += peer->p_hdr.info.pi_lft; + peer->p_exp_timer.tv_sec += peer->p_hdr.info.config.pic_lft; /* add to the expiry list in appropriate position (probably around the end) */ for (li = exp_list.prev; li != &exp_list; li = li->prev) { diff -r 1498b3c7304c -r cc3c59fe98fe freeDiameter/p_out.c --- a/freeDiameter/p_out.c Mon Nov 02 17:31:36 2009 +0900 +++ b/freeDiameter/p_out.c Thu Nov 05 14:28:46 2009 +0900 @@ -139,7 +139,7 @@ TRACE_ENTRY("%p %p %p", msg, cnx, peer); CHECK_PARAMS( msg && *msg && (cnx || (peer && peer->p_cnxctx))); - if (peer && (peer->p_hdr.info.pi_state == STATE_OPEN)) { + if (peer && (peer->p_hdr.info.runtime.pir_state == STATE_OPEN)) { /* Normal case: just queue for the out thread to pick it up */ CHECK_FCT( fd_fifo_post(peer->p_tosend, msg) ); diff -r 1498b3c7304c -r cc3c59fe98fe freeDiameter/p_psm.c --- a/freeDiameter/p_psm.c Mon Nov 02 17:31:36 2009 +0900 +++ b/freeDiameter/p_psm.c Thu Nov 05 14:28:46 2009 +0900 @@ -94,7 +94,7 @@ CHECK_FCT_DO( (*peer->p_cb2)(&peer->p_hdr.info), { TRACE_DEBUG(FULL, "Validation failed, moving to state CLOSING"); - peer->p_hdr.info.pi_state = STATE_CLOSING; + peer->p_hdr.info.runtime.pir_state = STATE_CLOSING; fd_psm_terminate(peer); } ); peer->p_cb2 = NULL; @@ -122,6 +122,9 @@ /* Start the thread to handle outgoing messages */ CHECK_FCT( fd_out_start(peer) ); + /* Update the expiry timer now */ + CHECK_FCT( fd_p_expi_update(peer) ); + return 0; } static int leave_open_state(struct fd_peer * peer) @@ -144,6 +147,32 @@ /************************************************************************/ /* Helpers for state changes */ /************************************************************************/ + +/* Cleanup pending events in the peer */ +void fd_psm_events_free(struct fd_peer * peer) +{ + struct fd_event * ev; + /* Purge all events, and free the associated data if any */ + while (fd_fifo_tryget( peer->p_events, &ev ) == 0) { + switch (ev->code) { + case FDEVP_CNX_ESTABLISHED: { + fd_cnx_destroy(ev->data); + } + break; + + case FDEVP_CNX_INCOMING: { + struct cnx_incoming * evd = ev->data; + CHECK_FCT_DO( fd_msg_free(evd->cer), /* continue */); + fd_cnx_destroy(evd->cnx); + } + default: + free(ev->data); + } + free(ev); + } +} + + /* Change state */ int fd_psm_change_state(struct fd_peer * peer, int new_state) { @@ -151,7 +180,7 @@ TRACE_ENTRY("%p %d(%s)", peer, new_state, STATE_STR(new_state)); CHECK_PARAMS( CHECK_PEER(peer) ); - old = peer->p_hdr.info.pi_state; + old = peer->p_hdr.info.runtime.pir_state; if (old == new_state) return 0; @@ -164,14 +193,20 @@ CHECK_FCT( leave_open_state(peer) ); } - peer->p_hdr.info.pi_state = new_state; + peer->p_hdr.info.runtime.pir_state = new_state; if (new_state == STATE_OPEN) { CHECK_FCT( enter_open_state(peer) ); } - if ((new_state == STATE_CLOSED) && (peer->p_hdr.info.pi_flags.persist == PI_PRST_NONE)) { - CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) ); + if (new_state == STATE_CLOSED) { + /* Purge event list */ + fd_psm_events_free(peer); + + /* If the peer is not persistant, we destroy it */ + if (peer->p_hdr.info.config.pic_flags.persist == PI_PRST_NONE) { + CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) ); + } } return 0; @@ -209,17 +244,23 @@ /* Cleanup the peer */ void fd_psm_cleanup(struct fd_peer * peer) { - /* Move to CLOSED state */ + /* Move to CLOSED state: failover messages, stop OUT thread, unlink peer from active list */ CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), /* continue */ ); - /* Destroy the connection */ + /* Destroy data */ + CHECK_FCT_DO( fd_thr_term(&peer->p_ini_thr), /* continue */); if (peer->p_cnxctx) { fd_cnx_destroy(peer->p_cnxctx); peer->p_cnxctx = NULL; } - - /* What else ? */ - TODO("..."); + if (peer->p_initiator) { + fd_cnx_destroy(peer->p_initiator); + peer->p_initiator = NULL; + } + if (peer->p_receiver) { + fd_cnx_destroy(peer->p_receiver); + peer->p_receiver = NULL; + } } @@ -232,7 +273,7 @@ { struct fd_peer * peer = (struct fd_peer *)arg; CHECK_PARAMS_DO( CHECK_PEER(peer), return ); - peer->p_hdr.info.pi_state = STATE_ZOMBIE; + peer->p_hdr.info.runtime.pir_state = STATE_ZOMBIE; return; } @@ -257,7 +298,7 @@ } /* The state machine starts in CLOSED state */ - peer->p_hdr.info.pi_state = STATE_CLOSED; + peer->p_hdr.info.runtime.pir_state = STATE_CLOSED; /* Wait that the PSM are authorized to start in the daemon */ CHECK_FCT_DO( fd_psm_waitstart(), goto psm_end ); @@ -273,16 +314,16 @@ /* Get next event */ CHECK_FCT_DO( fd_event_timedget(peer->p_events, &peer->p_psm_timer, FDEVP_PSM_TIMEOUT, &event, &ev_sz, &ev_data), goto psm_end ); TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p,%zd)\t'%s'", - STATE_STR(peer->p_hdr.info.pi_state), + STATE_STR(peer->p_hdr.info.runtime.pir_state), fd_pev_str(event), ev_data, ev_sz, peer->p_hdr.info.pi_diamid); /* Now, the action depends on the current state and the incoming event */ /* The following states are impossible */ - ASSERT( peer->p_hdr.info.pi_state != STATE_NEW ); - ASSERT( peer->p_hdr.info.pi_state != STATE_ZOMBIE ); - ASSERT( peer->p_hdr.info.pi_state != STATE_OPEN_HANDSHAKE ); /* because it exists only between two loops */ + ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_NEW ); + ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE ); + ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_OPEN_HANDSHAKE ); /* because it exists only between two loops */ /* Purge invalid events */ if (!CHECK_PEVENT(event)) { @@ -298,7 +339,7 @@ /* Requests to terminate the peer object */ if (event == FDEVP_TERMINATE) { - switch (peer->p_hdr.info.pi_state) { + switch (peer->p_hdr.info.runtime.pir_state) { case STATE_OPEN: case STATE_REOPEN: /* We cannot just close the conenction, we have to send a DPR first */ @@ -324,6 +365,13 @@ struct msg * msg = NULL; struct msg_hdr * hdr; + /* If the current state does not allow receiving messages, just drop it */ + if (peer->p_hdr.info.runtime.pir_state == STATE_CLOSED) { + TRACE_DEBUG(FULL, "Purging message in queue while in CLOSED state (%zdb)", ev_sz); + free(ev_data); + goto psm_loop; + } + /* Parse the received buffer */ CHECK_FCT_DO( fd_msg_parse_buffer( (void *)&ev_data, ev_sz, &msg), { @@ -338,13 +386,13 @@ /* Extract the header */ CHECK_FCT_DO( fd_msg_hdr(msg, &hdr), goto psm_end ); - /* If it is an answer, associate with the request */ + /* If it is an answer, associate with the request or drop */ if (!(hdr->msg_flags & CMD_FLAG_REQUEST)) { struct msg * req; /* Search matching request (same hbhid) */ CHECK_FCT_DO( fd_p_sr_fetch(&peer->p_sr, hdr->msg_hbhid, &req), goto psm_end ); if (req == NULL) { - fd_log_debug("Received a Diameter answer message with no corresponding sent request, discarding...\n"); + fd_log_debug("Received a Diameter answer message with no corresponding sent request, discarding.\n"); fd_msg_dump_walk(NONE, msg); fd_msg_free(msg); goto psm_loop; @@ -356,30 +404,44 @@ /* Now handle non-link-local messages */ if (fd_msg_is_routable(msg)) { - /* If we are not in OPEN state, discard the message */ - if (peer->p_hdr.info.pi_state != STATE_OPEN) { - fd_log_debug("Received a routable message while not in OPEN state from peer '%s', discarded.\n", peer->p_hdr.info.pi_diamid); - fd_msg_dump_walk(NONE, msg); - fd_msg_free(msg); - } else { - /* We received a valid message, update the expiry timer */ - CHECK_FCT_DO( fd_p_expi_update(peer), goto psm_end ); + switch (peer->p_hdr.info.runtime.pir_state) { + /* To maximize compatibility -- should not be a security issue here */ + case STATE_REOPEN: + case STATE_SUSPECT: + case STATE_CLOSING: + TRACE_DEBUG(FULL, "Accepted a message while not in OPEN state"); + /* The standard situation : */ + case STATE_OPEN: + /* We received a valid message, update the expiry timer */ + CHECK_FCT_DO( fd_p_expi_update(peer), goto psm_end ); + + /* Set the message source and add the Route-Record */ + CHECK_FCT_DO( fd_msg_source_set( msg, peer->p_hdr.info.pi_diamid, 1, fd_g_config->cnf_dict ), goto psm_end); + + /* Requeue to the global incoming queue */ + CHECK_FCT_DO(fd_fifo_post(fd_g_incoming, &msg), goto psm_end ); - /* Set the message source and add the Route-Record */ - CHECK_FCT_DO( fd_msg_source_set( msg, peer->p_hdr.info.pi_diamid, 1, fd_g_config->cnf_dict ), goto psm_end); - - /* Requeue to the global incoming queue */ - CHECK_FCT_DO(fd_fifo_post(fd_g_incoming, &msg), goto psm_end ); - - /* Update the peer timer */ - if (!peer->p_flags.pf_dw_pending) { - fd_psm_next_timeout(peer, 1, peer->p_hdr.info.pi_twtimer ?: fd_g_config->cnf_timer_tw); - } + /* Update the peer timer (only in OPEN state) */ + if ((peer->p_hdr.info.runtime.pir_state == STATE_OPEN) && (!peer->p_flags.pf_dw_pending)) { + fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw); + } + break; + + /* In other states, we discard the message, it is either old or invalid to send it for the remote peer */ + case STATE_WAITCNXACK: + case STATE_WAITCNXACK_ELEC: + case STATE_WAITCEA: + case STATE_CLOSED: + default: + /* In such case, just discard the message */ + fd_log_debug("Received a routable message while not in OPEN state from peer '%s', discarded.\n", peer->p_hdr.info.pi_diamid); + fd_msg_dump_walk(NONE, msg); + fd_msg_free(msg); } goto psm_loop; } - /* Link-local message: They must be understood by our dictionary */ + /* Link-local message: They must be understood by our dictionary, otherwise we return an error */ { int ret; CHECK_FCT_DO( ret = fd_msg_parse_or_error( &msg ), @@ -395,25 +457,45 @@ } ); } - ASSERT( hdr->msg_appl == 0 ); /* buggy fd_msg_is_routable() ? */ - /* Handle the LL message and update the expiry timer appropriately */ switch (hdr->msg_code) { - case CC_DEVICE_WATCHDOG: - CHECK_FCT_DO( fd_p_dw_handle(&msg, peer), goto psm_end ); + case CC_CAPABILITIES_EXCHANGE: + CHECK_FCT_DO( fd_p_ce_handle(&msg, peer), goto psm_end ); break; case CC_DISCONNECT_PEER: CHECK_FCT_DO( fd_p_dp_handle(&msg, peer), goto psm_end ); break; - case CC_CAPABILITIES_EXCHANGE: - CHECK_FCT_DO( fd_p_ce_handle(&msg, peer), goto psm_end ); + case CC_DEVICE_WATCHDOG: + CHECK_FCT_DO( fd_p_dw_handle(&msg, peer), goto psm_end ); break; default: /* Unknown / unexpected / invalid message */ - TODO("Log, return error message if request"); + fd_log_debug("Received an unknown local message from peer '%s', discarded.\n", peer->p_hdr.info.pi_diamid); + fd_msg_dump_walk(NONE, msg); + if (hdr->msg_flags & CMD_FLAG_REQUEST) { + do { + /* Reply with an error code */ + CHECK_FCT_DO( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &msg, MSGFL_ANSW_ERROR ), break ); + + /* Set the error code */ + CHECK_FCT_DO( fd_msg_rescode_set(msg, "DIAMETER_INVALID_HDR_BITS", NULL, NULL, 1 ), break ); + + /* Send the answer */ + CHECK_FCT_DO( fd_out_send(&msg, peer->p_cnxctx, peer), break ); + } while (0); + } else { + /* We did ASK for it ??? */ + fd_log_debug("Invalid PXY flag in header ?\n"); + } + + /* Cleanup the message if not done */ + if (msg) { + CHECK_FCT_DO( fd_msg_free(msg), /* continue */); + msg = NULL; + } }; /* At this point the message must have been fully handled already */ @@ -428,24 +510,37 @@ /* The connection object is broken */ if (event == FDEVP_CNX_ERROR) { - /* Cleanup the peer */ - fd_psm_cleanup(peer); - - /* Mark the connection problem */ - peer->p_flags.pf_cnx_pb = 1; - - /* Move to CLOSED */ - CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), goto psm_end ); - - /* Reset the timer */ - fd_psm_next_timeout(peer, 1, peer->p_hdr.info.pi_tctimer ?: fd_g_config->cnf_timer_tc); - - /* Loop */ - goto psm_loop; + switch (peer->p_hdr.info.runtime.pir_state) { + case STATE_WAITCNXACK_ELEC: + TODO("Reply CEA on the receiver side and go to OPEN state"); + goto psm_loop; + + case STATE_OPEN: + case STATE_REOPEN: + case STATE_WAITCNXACK: + case STATE_WAITCEA: + case STATE_SUSPECT: + default: + /* Mark the connection problem */ + peer->p_flags.pf_cnx_pb = 1; + + case STATE_CLOSING: + /* Cleanup the peer */ + fd_psm_cleanup(peer); + + /* Reset the timer */ + fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc); + + case STATE_CLOSED: + /* Go to the next event */ + goto psm_loop; + } } /* The connection notified a change in endpoints */ if (event == FDEVP_CNX_EP_CHANGE) { + /* We actually don't care if we are in OPEN state here... */ + /* Cleanup the remote LL and primary addresses */ CHECK_FCT_DO( fd_ep_filter( &peer->p_hdr.info.pi_endpoints, EP_FL_CONF | EP_FL_DISC | EP_FL_ADV ), /* ignore the error */); CHECK_FCT_DO( fd_ep_clearflags( &peer->p_hdr.info.pi_endpoints, EP_FL_PRIMARY ), /* ignore the error */); @@ -453,8 +548,10 @@ /* Get the new ones */ CHECK_FCT_DO( fd_cnx_getendpoints(peer->p_cnxctx, NULL, &peer->p_hdr.info.pi_endpoints), /* ignore the error */); + /* We do not support local endpoints change currently, but it could be added here if needed */ + if (TRACE_BOOL(ANNOYING)) { - fd_log_debug("New remote endpoint(s):\n"); + TRACE_DEBUG(ANNOYING, "New remote endpoint(s):" ); fd_ep_dump(6, &peer->p_hdr.info.pi_endpoints); } @@ -487,14 +584,16 @@ /* The timeout for the current state has been reached */ if (event == FDEVP_PSM_TIMEOUT) { - switch (peer->p_hdr.info.pi_state) { + switch (peer->p_hdr.info.runtime.pir_state) { case STATE_OPEN: case STATE_REOPEN: CHECK_FCT_DO( fd_p_dw_timeout(peer), goto psm_end ); break; case STATE_CLOSED: - TODO("Initiate a new connection"); + CHECK_FCT_DO( fd_psm_change_state(peer, STATE_WAITCNXACK), goto psm_end ); + fd_psm_next_timeout(peer, 0, CNX_TIMEOUT); + CHECK_FCT_DO( fd_p_cnx_init(peer), goto psm_end ); break; case STATE_CLOSING: @@ -503,8 +602,7 @@ case STATE_WAITCEA: /* Destroy the connection, restart the timer to a new connection attempt */ fd_psm_cleanup(peer); - fd_psm_next_timeout(peer, 1, peer->p_hdr.info.pi_tctimer ?: fd_g_config->cnf_timer_tc); - CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), goto psm_end ); + fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc); break; case STATE_WAITCNXACK_ELEC: @@ -514,7 +612,7 @@ } /* Default action : the handling has not yet been implemented. [for debug only] */ - TODO("Missing handler in PSM : '%s'\t<-- '%s'", STATE_STR(peer->p_hdr.info.pi_state), fd_pev_str(event)); + TODO("Missing handler in PSM : '%s'\t<-- '%s'", STATE_STR(peer->p_hdr.info.runtime.pir_state), fd_pev_str(event)); if (event == FDEVP_PSM_TIMEOUT) { /* We have not handled timeout in this state, let's postpone next alert */ fd_psm_next_timeout(peer, 0, 60); @@ -524,6 +622,7 @@ psm_end: fd_psm_cleanup(peer); + CHECK_FCT_DO( fd_fifo_del(&peer->p_events), /* continue */ ); pthread_cleanup_pop(1); /* set STATE_ZOMBIE */ peer->p_psm = (pthread_t)NULL; pthread_detach(pthread_self()); @@ -540,7 +639,10 @@ TRACE_ENTRY("%p", peer); /* Check the peer and state are OK */ - CHECK_PARAMS( CHECK_PEER(peer) && (peer->p_hdr.info.pi_state == STATE_NEW) ); + CHECK_PARAMS( CHECK_PEER(peer) && (peer->p_hdr.info.runtime.pir_state == STATE_NEW) ); + + /* Create the FIFO for events */ + CHECK_FCT( fd_fifo_new(&peer->p_events) ); /* Create the PSM controler thread */ CHECK_POSIX( pthread_create( &peer->p_psm, NULL, p_psm_th, peer ) ); @@ -555,7 +657,7 @@ TRACE_ENTRY("%p", peer); CHECK_PARAMS( CHECK_PEER(peer) ); - if (peer->p_hdr.info.pi_state != STATE_ZOMBIE) { + if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) { CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) ); } else { TRACE_DEBUG(FULL, "Peer '%s' was already terminated", peer->p_hdr.info.pi_diamid); @@ -571,21 +673,13 @@ /* Cancel PSM thread */ CHECK_FCT_DO( fd_thr_term(&peer->p_psm), /* continue */ ); - /* Cancel the OUT thread */ - CHECK_FCT_DO( fd_out_stop(peer), /* continue */ ); - - /* Cleanup the connection */ - if (peer->p_cnxctx) { - fd_cnx_destroy(peer->p_cnxctx); - } + /* Cleanup the data */ + fd_psm_cleanup(peer); - /* Failover the messages */ - fd_peer_failover_msg(peer); + /* Destroy the event list */ + CHECK_FCT_DO( fd_fifo_del(&peer->p_events), /* continue */ ); - /* Empty the events list, this might leak some memory, but we only do it on exit, so... */ - fd_event_destroy(&peer->p_events, free); - - /* More cleanups are performed in fd_peer_free */ + /* Remaining cleanups are performed in fd_peer_free */ return; } diff -r 1498b3c7304c -r cc3c59fe98fe freeDiameter/peers.c --- a/freeDiameter/peers.c Mon Nov 02 17:31:36 2009 +0900 +++ b/freeDiameter/peers.c Thu Nov 05 14:28:46 2009 +0900 @@ -68,15 +68,15 @@ fd_list_init(&p->p_hdr.chain, p); - fd_list_init(&p->p_hdr.info.pi_endpoints, NULL); - fd_list_init(&p->p_hdr.info.pi_apps, NULL); + fd_list_init(&p->p_hdr.info.pi_endpoints, p); + fd_list_init(&p->p_hdr.info.runtime.pir_apps, p); p->p_eyec = EYEC_PEER; + fd_list_init(&p->p_actives, p); fd_list_init(&p->p_expiry, p); - fd_list_init(&p->p_actives, p); + CHECK_FCT( fd_fifo_new(&p->p_tosend) ); p->p_hbh = lrand48(); - CHECK_FCT( fd_fifo_new(&p->p_events) ); - CHECK_FCT( fd_fifo_new(&p->p_tosend) ); + fd_list_init(&p->p_sr.srs, p); CHECK_POSIX( pthread_mutex_init(&p->p_sr.mtx, NULL) ); @@ -97,27 +97,17 @@ /* Copy the informations from the parameters received */ CHECK_MALLOC( p->p_hdr.info.pi_diamid = strdup(info->pi_diamid) ); - if (info->pi_realm) { - CHECK_MALLOC( p->p_hdr.info.pi_realm = strdup(info->pi_realm) ); + + memcpy( &p->p_hdr.info.config, &info->config, sizeof(p->p_hdr.info.config) ); + /* Duplicate the strings if provided */ + if (info->config.pic_realm) { + CHECK_MALLOC( p->p_hdr.info.config.pic_realm = strdup(info->config.pic_realm) ); + } + if (info->config.pic_priority) { + CHECK_MALLOC( p->p_hdr.info.config.pic_realm = strdup(info->config.pic_priority) ); } - p->p_hdr.info.pi_flags.pro3 = info->pi_flags.pro3; - p->p_hdr.info.pi_flags.pro4 = info->pi_flags.pro4; - p->p_hdr.info.pi_flags.alg = info->pi_flags.alg; - p->p_hdr.info.pi_flags.sec = info->pi_flags.sec; - p->p_hdr.info.pi_flags.exp = info->pi_flags.exp; - p->p_hdr.info.pi_flags.persist = info->pi_flags.persist; - - p->p_hdr.info.pi_lft = info->pi_lft; - p->p_hdr.info.pi_port = info->pi_port; - p->p_hdr.info.pi_tctimer = info->pi_tctimer; - p->p_hdr.info.pi_twtimer = info->pi_twtimer; - - if (info->pi_sec_data.priority) { - CHECK_MALLOC( p->p_hdr.info.pi_sec_data.priority = strdup(info->pi_sec_data.priority) ); - } - - /* Move the items from one list to the other */ + /* Move the list of endpoints into the peer */ if (info->pi_endpoints.next) while (!FD_IS_LIST_EMPTY( &info->pi_endpoints ) ) { li = info->pi_endpoints.next; @@ -125,7 +115,6 @@ fd_list_insert_before(&p->p_hdr.info.pi_endpoints, li); } - /* The internal data */ if (orig_dbg) { CHECK_MALLOC( p->p_dbgorig = strdup(orig_dbg) ); @@ -149,15 +138,15 @@ } /* We can insert the new peer object */ - if (! ret) { - /* Update expiry list */ - CHECK_FCT_DO( ret = fd_p_expi_update( p ), goto out ); - - /* Insert the new element in the list */ - fd_list_insert_before( li, &p->p_hdr.chain ); - } + if (! ret) + do { + /* Update expiry list */ + CHECK_FCT_DO( ret = fd_p_expi_update( p ), break ); -out: + /* Insert the new element in the list */ + fd_list_insert_before( li, &p->p_hdr.chain ); + } while (0); + CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) ); if (ret) { CHECK_FCT( fd_peer_free(&p) ); @@ -202,7 +191,7 @@ return; } -/* Destroy a structure once all cleanups have been performed */ +/* Destroy a structure once cleanups have been performed (fd_psm_abord, ...) */ int fd_peer_free(struct fd_peer ** ptr) { struct fd_peer *p; @@ -216,33 +205,22 @@ CHECK_PARAMS( FD_IS_LIST_EMPTY(&p->p_hdr.chain) ); - free_null(p->p_hdr.info.pi_diamid); - free_null(p->p_hdr.info.pi_realm); + free_null(p->p_hdr.info.pi_diamid); + + free_null(p->p_hdr.info.config.pic_realm); + free_null(p->p_hdr.info.config.pic_priority); + + free_null(p->p_hdr.info.runtime.pir_realm); + free_null(p->p_hdr.info.runtime.pir_prodname); + free_list( &p->p_hdr.info.runtime.pir_apps ); + free_list( &p->p_hdr.info.pi_endpoints ); - TODO("Free the security data if any ?"); - free_null(p->p_hdr.info.pi_prodname); - free_list( &p->p_hdr.info.pi_apps ); free_null(p->p_dbgorig); - ASSERT(FD_IS_LIST_EMPTY(&p->p_expiry)); - ASSERT(FD_IS_LIST_EMPTY(&p->p_actives)); - CHECK_FCT( fd_thr_term(&p->p_psm) ); - while ( fd_fifo_tryget(p->p_events, &t) == 0 ) { - struct fd_event * ev = t; - TRACE_DEBUG(FULL, "Found event %d(%p) in queue of peer %p being destroyed", ev->code, ev->data, p); - free(ev); - } - CHECK_FCT( fd_fifo_del(&p->p_events) ); + fd_list_unlink(&p->p_expiry); + fd_list_unlink(&p->p_actives); - CHECK_FCT( fd_thr_term(&p->p_outthr) ); - - if (p->p_cnxctx) { - fd_cnx_destroy(p->p_cnxctx); - } - - /* Requeue any remaining message into global structures if possible */ - fd_peer_failover_msg(p); CHECK_FCT_DO( fd_fifo_del(&p->p_tosend), /* continue */ ); CHECK_POSIX_DO( pthread_mutex_destroy(&p->p_sr.mtx), /* continue */); @@ -255,7 +233,7 @@ return 0; } -/* Terminate peer module (destroy all peers) */ +/* Terminate peer module (destroy all peers, first gently, then violently) */ int fd_peer_fini() { struct fd_list * li; @@ -273,7 +251,7 @@ for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) { struct fd_peer * peer = (struct fd_peer *)li; - if (peer->p_hdr.info.pi_state != STATE_ZOMBIE) { + if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) { CHECK_FCT_DO( fd_psm_terminate(peer), /* continue */ ); } else { li = li->prev; /* to avoid breaking the loop */ @@ -286,8 +264,8 @@ if (!list_empty) { CHECK_SYS( clock_gettime(CLOCK_REALTIME, &now) ); - TRACE_DEBUG(INFO, "Waiting for connections shutdown... (%d sec max)", DPR_TIMEOUT); - wait_until.tv_sec = now.tv_sec + DPR_TIMEOUT; + TRACE_DEBUG(INFO, "Waiting for connections shutdown... (%d sec max)", DPR_TIMEOUT + 1); + wait_until.tv_sec = now.tv_sec + DPR_TIMEOUT + 1; wait_until.tv_nsec = now.tv_nsec; } @@ -300,7 +278,7 @@ CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), /* continue */ ); for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) { struct fd_peer * peer = (struct fd_peer *)li; - if (peer->p_hdr.info.pi_state == STATE_ZOMBIE) { + if (peer->p_hdr.info.runtime.pir_state == STATE_ZOMBIE) { li = li->prev; /* to avoid breaking the loop */ fd_list_unlink(&peer->p_hdr.chain); fd_list_insert_before(&purge, &peer->p_hdr.chain); @@ -350,32 +328,28 @@ return; } - fd_log_debug("> %s\t%s", STATE_STR(peer->p_hdr.info.pi_state), peer->p_hdr.info.pi_diamid); + fd_log_debug("> %s\t%s", STATE_STR(peer->p_hdr.info.runtime.pir_state), peer->p_hdr.info.pi_diamid); if (details > INFO) { - fd_log_debug("\t(rlm:%s)", peer->p_hdr.info.pi_realm); - if (peer->p_hdr.info.pi_prodname) - fd_log_debug("\t['%s' %u]", peer->p_hdr.info.pi_prodname, peer->p_hdr.info.pi_firmrev); + fd_log_debug("\t(rlm:%s)", peer->p_hdr.info.runtime.pir_realm ?: "(unknown)"); + if (peer->p_hdr.info.runtime.pir_prodname) + fd_log_debug("\t['%s' %u]", peer->p_hdr.info.runtime.pir_prodname, peer->p_hdr.info.runtime.pir_firmrev); } fd_log_debug("\n"); if (details > FULL) { /* Dump all info */ - fd_log_debug("\tEntry origin : %s\n", peer->p_dbgorig); - fd_log_debug("\tFlags : %s%s%s%s%s - %s%s%s\n", - peer->p_hdr.info.pi_flags.pro3 == PI_P3_DEFAULT ? "" : - (peer->p_hdr.info.pi_flags.pro3 == PI_P3_IP ? "IP." : "IPv6."), - peer->p_hdr.info.pi_flags.pro4 == PI_P4_DEFAULT ? "" : - (peer->p_hdr.info.pi_flags.pro4 == PI_P4_TCP ? "TCP." : "SCTP."), - peer->p_hdr.info.pi_flags.alg ? "PrefTCP." : "", - peer->p_hdr.info.pi_flags.sec == PI_SEC_DEFAULT ? "" : - (peer->p_hdr.info.pi_flags.sec == PI_SEC_NONE ? "IPSec." : "InbandTLS."), - peer->p_hdr.info.pi_flags.exp ? "Expire." : "", - peer->p_hdr.info.pi_flags.inband_none ? "InbandIPsec." : "", - peer->p_hdr.info.pi_flags.inband_tls ? "InbandTLS." : "", - peer->p_hdr.info.pi_flags.relay ? "Relay (0xffffff)" : "No relay" + fd_log_debug("\tEntry origin : %s\n", peer->p_dbgorig?: "not set"); + fd_log_debug("\tConfig flags : %s%s%s%s%s - %s%s%s\n", + peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_DEFAULT ? "" : + (peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP ? "IP." : "IPv6."), + peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_DEFAULT ? "" : + (peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_TCP ? "TCP." : "SCTP."), + peer->p_hdr.info.config.pic_flags.alg ? "PrefTCP." : "", + peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE ? "NoTLSok" :"", + peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD ? "OldTLS" :"", + peer->p_hdr.info.config.pic_flags.exp ? "Expire." : "", + peer->p_hdr.info.config.pic_flags.persist ? "Persist." : "" ); - fd_log_debug("\tLifetime : %d sec\n", peer->p_hdr.info.pi_lft); - - TODO("Dump remaining useful information"); + fd_log_debug("\tLifetime : %d sec\n", peer->p_hdr.info.config.pic_lft); } } @@ -443,8 +417,8 @@ peer->p_flags.pf_responder = 1; /* Set this peer to expire on inactivity */ - peer->p_hdr.info.pi_flags.exp = PI_EXP_INACTIVE; - peer->p_hdr.info.pi_lft = 3600 * 3; /* 3 hours without any message */ + peer->p_hdr.info.config.pic_flags.exp = PI_EXP_INACTIVE; + peer->p_hdr.info.config.pic_lft = 3600 * 3; /* 3 hours without any message */ /* Upgrade the lock to write lock */ CHECK_POSIX_DO( ret = pthread_rwlock_wrlock(&fd_g_peers_rw), goto out ); diff -r 1498b3c7304c -r cc3c59fe98fe include/freeDiameter/freeDiameter.h --- a/include/freeDiameter/freeDiameter.h Mon Nov 02 17:31:36 2009 +0900 +++ b/include/freeDiameter/freeDiameter.h Thu Nov 05 14:28:46 2009 +0900 @@ -276,68 +276,75 @@ #define STATE_STR(state) \ (((unsigned)(state)) <= STATE_MAX ? peer_state_str[((unsigned)(state)) ] : "") -/* Information about a remote peer. Same structure is used for creating a new entry, but not all fields are meaningful in that case */ +/* Information about a remote peer */ struct peer_info { - char * pi_diamid; /* UTF-8, \0 terminated. The Diameter Identity of the remote peer */ - char * pi_realm; /* Its realm, as received in CER/CEA exchange. */ + char * pi_diamid; /* UTF-8, \0 terminated. The Diameter Identity of the remote peer. */ struct { - #define PI_P3_DEFAULT 0 /* Use the default L3 protocol configured for the host */ - #define PI_P3_IP 1 /* Use only IP to connect to this peer */ - #define PI_P3_IPv6 2 /* resp, IPv6 */ - unsigned pro3 :2; - - #define PI_P4_DEFAULT 0 /* Use the default L4 proto configured for the host */ - #define PI_P4_TCP 1 /* Only use TCP */ - #define PI_P4_SCTP 2 /* Only use SCTP */ - unsigned pro4 :2; - - #define PI_ALGPREF_SCTP 0 /* SCTP is initially attempted */ - #define PI_ALGPREF_TCP 1 /* TCP is initially attempted */ - unsigned alg :1; - - #define PI_SEC_DEFAULT 0 /* New TLS security (dedicated port protecting also CER/CEA) */ - #define PI_SEC_NONE 1 /* Transparent security with this peer (IPsec) */ - #define PI_SEC_TLS_OLD 2 /* Old TLS security (inband on default port) */ - unsigned sec :2; + struct { + #define PI_P3_DEFAULT 0 /* Use any available protocol */ + #define PI_P3_IP 1 /* Use only IP to connect to this peer */ + #define PI_P3_IPv6 2 /* resp, IPv6 */ + unsigned pro3 :2; + + #define PI_P4_DEFAULT 0 /* Attempt any available protocol */ + #define PI_P4_TCP 1 /* Only use TCP */ + #define PI_P4_SCTP 2 /* Only use SCTP */ + unsigned pro4 :2; + + #define PI_ALGPREF_SCTP 0 /* SCTP is attempted first (default) */ + #define PI_ALGPREF_TCP 1 /* TCP is attempted first */ + unsigned alg :1; + + #define PI_SEC_DEFAULT 0 /* New TLS security (handshake after connection, protecting also CER/CEA) */ + #define PI_SEC_NONE 1 /* Transparent security with this peer (IPsec) */ + #define PI_SEC_TLS_OLD 2 /* Old TLS security (use Inband-Security-Id AVP during CER/CEA) */ + unsigned sec :2; /* Set sec = 3 to authorize use of (Inband-Security-Id == NONE) with this peer, sec = 2 only authorizing TLS */ + + #define PI_EXP_NONE 0 /* the peer entry does not expire */ + #define PI_EXP_INACTIVE 1 /* the peer entry expires (i.e. is deleted) after pi_lft seconds without activity */ + unsigned exp :1; + + #define PI_PRST_NONE 0 /* the peer entry is deleted after disconnection / error */ + #define PI_PRST_ALWAYS 1 /* the peer entry is persistant (will be kept as ZOMBIE in case of error) */ + unsigned persist :1; + + } pic_flags; /* Flags influencing the connection to the remote peer */ - #define PI_EXP_NONE 0 /* the peer entry does not expire */ - #define PI_EXP_INACTIVE 1 /* the peer entry expires (i.e. is deleted) after pi_lft seconds without activity */ - unsigned exp :1; + char * pic_realm; /* If configured, the daemon will match the received realm in CER/CEA matches this. */ + uint16_t pic_port; /* port to connect to. 0: default. */ + + uint32_t pic_lft; /* lifetime of this peer when inactive (see pic_flags.exp definition) */ + int pic_tctimer; /* use this value for TcTimer instead of global, if != 0 */ + int pic_twtimer; /* use this value for TwTimer instead of global, if != 0 */ - #define PI_PRST_NONE 0 /* the peer entry is deleted after disconnection / error */ - #define PI_PRST_ALWAYS 1 /* the peer entry is persistant (will be kept as ZOMBIE in case of error) */ - unsigned persist :1; + char * pic_priority; /* Priority string for GnuTLS if we don't use the default */ + + } config; /* Configured data (static for this peer entry) */ + + struct { + + enum peer_state pir_state; /* Current state of the peer in the state machine */ - unsigned inband_none :1; /* This is only meaningful with pi_flags.sec == 3 */ - unsigned inband_tls :1; /* This is only meaningful with pi_flags.sec == 3 */ + char * pir_realm; /* The received realm in CER/CEA. */ - unsigned relay :1; /* The remote peer advertized the relay application */ - - } pi_flags; /* Some flags */ - - /* Additional parameters */ - uint32_t pi_lft; /* lifetime of this peer when inactive (see pi_flags.exp definition) */ - uint16_t pi_port; /* port to connect to. 0: default. */ - int pi_tctimer; /* use this value for TcTimer instead of global, if != 0 */ - int pi_twtimer; /* use this value for TwTimer instead of global, if != 0 */ + uint32_t pir_vendorid; /* Content of the Vendor-Id AVP, or 0 by default */ + uint32_t pir_orstate; /* Origin-State-Id value */ + char * pir_prodname; /* copy of UTF-8 Product-Name AVP (\0 terminated) */ + uint32_t pir_firmrev; /* Content of the Firmware-Revision AVP */ + int pir_relay; /* The remote peer advertized the relay application */ + struct fd_list pir_apps; /* applications advertised by the remote peer, except relay (pi_flags.relay) */ + + int pir_proto; /* The L4 protocol currently used with the peer (IPPROTO_TCP or IPPROTO_SCTP) */ + const gnutls_datum_t *pir_cert_list; /* The (valid) credentials that the peer has presented, or NULL if TLS is not used */ + /* This is inspired from http://www.gnu.org/software/gnutls/manual/gnutls.html#ex_003ax509_002dinfo + see there for example of using this data */ + unsigned int pir_cert_list_size; /* Number of certificates in the list */ + + } runtime; /* Data populated after connection, may change between 2 connections -- not used by fd_peer_add */ struct fd_list pi_endpoints; /* Endpoint(s) of the remote peer (configured, discovered, or advertized). list of struct fd_endpoint. DNS resolved if empty. */ - - /* The remaining information must not be modified, and is not used for peer creation */ - enum peer_state pi_state; - uint32_t pi_vendorid; /* Content of the Vendor-Id AVP, or 0 by default */ - uint32_t pi_orstate; /* Origin-State-Id value */ - char * pi_prodname; /* copy of UTF-8 Product-Name AVP (\0 terminated) */ - uint32_t pi_firmrev; /* Content of the Firmware-Revision AVP */ - struct fd_list pi_apps; /* applications advertised by the remote peer, except relay (pi_flags.relay) */ - struct { - char *priority; /* In case the default priority is not appropriate */ - /* This is inspired from http://www.gnu.org/software/gnutls/manual/gnutls.html#ex_003ax509_002dinfo see there for example of using this data */ - const gnutls_datum_t *cert_list; /* The (valid) credentials that the peer has presented */ - unsigned int cert_list_size;/* Number of certificates in the list */ - } pi_sec_data; }; struct peer_hdr { diff -r 1498b3c7304c -r cc3c59fe98fe libfreeDiameter/messages.c --- a/libfreeDiameter/messages.c Mon Nov 02 17:31:36 2009 +0900 +++ b/libfreeDiameter/messages.c Thu Nov 05 14:28:46 2009 +0900 @@ -1062,8 +1062,8 @@ CHECK_PARAMS_DO( CHECK_MSG(msg), return 0 /* pretend the message is not routable */ ); if ( ! msg->msg_routable ) { - /* To define if a message is routable, we rely on the "PXY" command flag yet. */ - msg->msg_routable = (msg->msg_public.msg_flags & CMD_FLAG_PROXIABLE) ? 1 : 2; + /* To define if a message is routable, we rely on the "PXY" flag (for application 0). */ + msg->msg_routable = ((msg->msg_public.msg_appl != 0) || (msg->msg_public.msg_flags & CMD_FLAG_PROXIABLE)) ? 1 : 2; /* Note : the 'real' criteria according to the Diameter I-D is that the message is routable if and only if the "Destination-Realm" AVP is required by the command ABNF.