Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
oai
freediameter
Commits
61193b7f
Commit
61193b7f
authored
Nov 05, 2009
by
Sebastien Decugis
Browse files
Lot of cleanups in peer structure management
parent
292243c1
Changes
11
Hide whitespace changes
Inline
Side-by-side
freeDiameter/CMakeLists.txt
View file @
61193b7f
...
...
@@ -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
...
...
freeDiameter/fD.h
View file @
61193b7f
...
...
@@ -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); \
...
...
freeDiameter/fdd.y
View file @
61193b7f
...
...
@@ -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.
pi
c
_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.
pi
c
_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.
pi
c
_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.
pi
c
_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.
pi
c
_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.
pi
c
_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.
pi
c
_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.
pi
c
_flags.pro4 = PI_P4_TCP;
}
| peerparams PREFERTCP ';'
{
fddpi.pi_flags.alg = PI_ALGPREF_TCP;
fddpi.
config.
pi
c
_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.
pi
c
_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.
pi
c
_port = (uint16_t)$4;
}
| peerparams TCTIMER '=' INTEGER ';'
{
fddpi.pi_tctimer = $4;
fddpi.
config.
pi
c
_tctimer = $4;
}
| peerparams T
LS_PRIO '=' QSTRING
';'
| peerparams T
WTIMER '=' INTEGER
';'
{
fddpi.
pi_sec_data.priority
= $4;
fddpi.
config.pic_twtimer
= $4;
}
| peerparams T
WTIMER '=' INTEGER
';'
| peerparams T
LS_PRIO '=' QSTRING
';'
{
fddpi.
pi_twtimer
= $4;
fddpi.
config.pic_priority
= $4;
}
| peerparams CONNTO '=' QSTRING ';'
{
...
...
freeDiameter/p_ce.c
View file @
61193b7f
...
...
@@ -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
.
pi
r
_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 */
...
...
freeDiameter/p_cnx.c
0 → 100644
View file @
61193b7f
/*********************************************************************************************************
* 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
;
}
freeDiameter/p_expiry.c
View file @
61193b7f
...
...
@@ -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
.
pi
r
_state
!=
STATE_ZOMBIE
)
continue
;
if
(
peer
->
p_hdr
.
info
.
pi_flags
.
persist
==
PI_PRST_ALWAYS
)
if
(
peer
->
p_hdr
.
info
.
config
.
pi
c
_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
.
pi
c
_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
.
pi
c
_lft
;
/* add to the expiry list in appropriate position (probably around the end) */
for
(
li
=
exp_list
.
prev
;
li
!=
&
exp_list
;
li
=
li
->
prev
)
{
...
...
freeDiameter/p_out.c
View file @
61193b7f
...
...
@@ -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
.
pi
r
_state
==
STATE_OPEN
))
{
/* Normal case: just queue for the out thread to pick it up */
CHECK_FCT
(
fd_fifo_post
(
peer
->
p_tosend
,
msg
)
);
...
...
freeDiameter/p_psm.c
View file @
61193b7f
...
...
@@ -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
.
pi
r
_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
.
pi
r
_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
.
pi
r
_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
.
pi
r
_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
.
pi
r
_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
.
pi
r
_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
.
pi
r
_state
!=
STATE_NEW
);
ASSERT
(
peer
->
p_hdr
.
info
.
runtime
.
pi
r
_state
!=
STATE_ZOMBIE
);
ASSERT
(
peer
->
p_hdr
.
info
.
runtime
.
pi
r
_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
.
pi
r
_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 */
);