Commit 61193b7f authored by Sebastien Decugis's avatar Sebastien Decugis
Browse files

Lot of cleanups in peer structure management

parent 292243c1
......@@ -20,6 +20,7 @@ SET(FD_COMMON_SRC
queues.c
peers.c
p_ce.c
p_cnx.c
p_dw.c
p_dp.c
p_expiry.c
......
......@@ -118,15 +118,13 @@ struct fd_peer { /* The "real" definition of the peer structure */
/* 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 @@ struct fd_peer { /* The "real" definition of the peer structure */
/* 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 @@ enum {
/* 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 @@ const char * fd_pev_str(int event) \
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); \
......
......@@ -315,9 +315,8 @@ extconf: /* empty */
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 @@ connpeer: {
/* 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 @@ peerinfo: /* empty */
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 @@ peerparams: /* empty */
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 TLS_PRIO '=' QSTRING ';'
| peerparams TWTIMER '=' INTEGER ';'
{
fddpi.pi_sec_data.priority = $4;
fddpi.config.pic_twtimer = $4;
}
| peerparams TWTIMER '=' INTEGER ';'
| peerparams TLS_PRIO '=' QSTRING ';'
{
fddpi.pi_twtimer = $4;
fddpi.config.pic_priority = $4;
}
| peerparams CONNTO '=' QSTRING ';'
{
......
......@@ -46,7 +46,7 @@ int fd_p_ce_handle(struct msg ** msg, struct fd_peer * peer)
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 */
......
/*********************************************************************************************************
* Software License Agreement (BSD License) *
* Author: Sebastien Decugis <sdecugis@nict.go.jp> *
* *
* 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;
}
......@@ -60,10 +60,10 @@ static void * gc_th_fct(void * arg)
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 @@ int fd_p_expi_fini(void)
{
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_FCT_DO( fd_thr_term(&gc_thr), );
return 0;
}
......@@ -179,12 +178,12 @@ int fd_p_expi_update(struct fd_peer * peer )
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) {
......
......@@ -139,7 +139,7 @@ int fd_out_send(struct msg ** msg, struct cnxctx * cnx, struct fd_peer * peer)
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) );
......
......@@ -94,7 +94,7 @@ static int enter_open_state(struct fd_peer * peer)
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 @@ static int enter_open_state(struct fd_peer * peer)
/* 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 @@ static int leave_open_state(struct fd_peer * peer)
/************************************************************************/
/* 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 @@ int fd_psm_change_state(struct fd_peer * peer, int new_state)
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 @@ int fd_psm_change_state(struct fd_peer * peer, int new_state)
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 @@ void fd_psm_next_timeout(struct fd_peer * peer, int add_random, int delay)
/* 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 @@ void cleanup_setstate(void * arg)
{
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 @@ static void * p_psm_th( void * arg )
}
/* 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 @@ psm_loop:
/* 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 @@ psm_loop:
/* 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 @@ psm_loop:
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 @@ psm_loop:
/* 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 @@ psm_loop:
/* 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);
/* 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);
}
/* Requeue to the global incoming queue */
CHECK_FCT_DO(fd_fifo_post(fd_g_incoming, &msg), goto psm_end );
/* 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 @@ psm_loop:
} );
}
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 */);