Navigation


source: freeDiameter/libfdcore/p_dp.c @ 706:4ffbc9f1e922

Last change on this file since 706:4ffbc9f1e922 was 706:4ffbc9f1e922, checked in by Sebastien Decugis <sdecugis@nict.go.jp>, 11 years ago

Large UNTESTED commit with the following changes:

  • Improved DiameterIdentity? handling (esp. interationalization issues), and improve efficiency of some string operations in peers, sessions, and dictionary modules (closes #7)
  • Cleanup in the session module to free only unreferenced sessions (#16)
  • Removed fd_cpu_flush_cache(), replaced by more robust alternatives.
  • Improved peer state machine algorithm to counter SCTP multistream race condition.
File size: 7.8 KB
Line 
1/*********************************************************************************************************
2* Software License Agreement (BSD License)                                                               *
3* Author: Sebastien Decugis <sdecugis@nict.go.jp>                                                        *
4*                                                                                                        *
5* Copyright (c) 2011, WIDE Project and NICT                                                              *
6* All rights reserved.                                                                                   *
7*                                                                                                        *
8* Redistribution and use of this software in source and binary forms, with or without modification, are  *
9* permitted provided that the following conditions are met:                                              *
10*                                                                                                        *
11* * Redistributions of source code must retain the above                                                 *
12*   copyright notice, this list of conditions and the                                                    *
13*   following disclaimer.                                                                                *
14*                                                                                                        *
15* * Redistributions in binary form must reproduce the above                                              *
16*   copyright notice, this list of conditions and the                                                    *
17*   following disclaimer in the documentation and/or other                                               *
18*   materials provided with the distribution.                                                            *
19*                                                                                                        *
20* * Neither the name of the WIDE Project or NICT nor the                                                 *
21*   names of its contributors may be used to endorse or                                                  *
22*   promote products derived from this software without                                                  *
23*   specific prior written permission of WIDE Project and                                                *
24*   NICT.                                                                                                *
25*                                                                                                        *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT     *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS    *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                                             *
34*********************************************************************************************************/
35
36#include "fdcore-internal.h"
37
38/* This file contains code to handle Disconnect Peer messages (DPR and DPA) */
39
40/* Delay to use before next reconnect attempt */
41int fd_p_dp_newdelay(struct fd_peer * peer) 
42{
43        int delay = peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc;
44       
45        switch (peer->p_hdr.info.runtime.pir_lastDC) {
46                case ACV_DC_REBOOTING:
47                default:
48                        /* We use TcTimer to attempt reconnection */
49                        break;
50                case ACV_DC_BUSY:
51                        /* No need to hammer the overloaded peer */
52                        delay *= 10;
53                        break;
54                case ACV_DC_NOT_FRIEND:
55                        /* He does not want to speak to us... let's retry a *lot* later maybe */
56                        delay *= 200;
57                        break;
58        }
59        return delay;
60}
61
62/* Handle a received message */
63int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer)
64{
65        TRACE_ENTRY("%p %d %p", msg, req, peer);
66       
67        if (req) {
68                /* We received a DPR, save the Disconnect-Cause and go to CLOSING_GRACE or terminate the connection */
69                struct avp * dc;
70               
71                CHECK_FCT( fd_msg_search_avp ( *msg, fd_dict_avp_DC, &dc ));
72                if (dc) {
73                        struct avp_hdr * hdr;
74                        CHECK_FCT(  fd_msg_avp_hdr( dc, &hdr )  );
75                        if (hdr->avp_value == NULL) {
76                                /* This is a sanity check */
77                                TRACE_DEBUG(NONE, "BUG: Unset value in Disconnect-Cause in DPR");
78                                fd_msg_dump_one(NONE, dc);
79                                ASSERT(0); /* To check if this really happens, and understand why... */
80                        }
81
82                        /* save the cause */
83                        peer->p_hdr.info.runtime.pir_lastDC = hdr->avp_value->u32;
84                }
85                if (TRACE_BOOL(INFO)) {
86                        if (dc) {
87                                struct dict_object * dictobj;
88                                struct dict_enumval_request er;
89                                memset(&er, 0, sizeof(er));
90                               
91                                /* prepare the request */
92                                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, fd_dict_avp_DC, &er.type_obj, ENOENT )  );
93                                er.search.enum_value.u32 = peer->p_hdr.info.runtime.pir_lastDC;
94                               
95                                /* Search the enum value */
96                                CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &er, &dictobj, 0 )  );
97                                if (dictobj) {
98                                        CHECK_FCT( fd_dict_getval( dictobj, &er.search ) );
99                                        TRACE_DEBUG(INFO, "Peer '%s' sent a DPR with cause: %s\n", peer->p_hdr.info.pi_diamid, er.search.enum_name);
100                                } else {
101                                        TRACE_DEBUG(INFO, "Peer '%s' sent a DPR with unknown cause: %u\n", peer->p_hdr.info.pi_diamid, peer->p_hdr.info.runtime.pir_lastDC);
102                                }
103                        } else {
104                                TRACE_DEBUG(INFO, "Peer '%s' sent a DPR without Disconnect-Cause AVP\n", peer->p_hdr.info.pi_diamid);
105                        }
106                }
107               
108                /* Now reply with a DPA */
109                CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, 0 ) );
110                CHECK_FCT( fd_msg_rescode_set( *msg, "DIAMETER_SUCCESS", NULL, NULL, 1 ) );
111               
112                /* Move to CLOSING state to failover outgoing messages (and avoid failing over the DPA...) */
113                CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING) );
114               
115                /* Now send the DPA */
116                CHECK_FCT( fd_out_send( msg, NULL, peer, FD_CNX_ORDERED) );
117               
118                if (fd_cnx_isMultichan(peer->p_cnxctx)) {
119                        /* There is a possibililty that messages are still in the pipe coming here, so let's grace for 1 second */
120                        CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING_GRACE) );
121                        fd_psm_next_timeout(peer, 0, 1);
122                       
123                } else {
124                        /* Move to CLOSED state */
125                        fd_psm_cleanup(peer, 0);
126
127                        /* Reset the timer for next connection attempt -- we'll retry sooner or later depending on the disconnection cause */
128                        fd_psm_next_timeout(peer, 1, fd_p_dp_newdelay(peer));
129                }
130        } else {
131                /* We received a DPA */
132                int curstate = fd_peer_getstate(peer);
133                if (curstate != STATE_CLOSING) {
134                        TRACE_DEBUG(INFO, "Ignoring DPA received in state %s", STATE_STR(curstate));
135                }
136                       
137                /* In theory, we should control the Result-Code AVP. But since we will not go back to OPEN state here anyway, let's skip it */
138               
139                /* TODO("Control Result-Code in the DPA") */
140                CHECK_FCT_DO( fd_msg_free( *msg ), /* continue */ );
141                *msg = NULL;
142               
143                if (fd_cnx_isMultichan(peer->p_cnxctx)) {
144                        CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING_GRACE) );
145                        fd_psm_next_timeout(peer, 0, 1);
146                        peer->p_flags.pf_localterm = 1;
147                }
148                /* otherwise, return in CLOSING state, the psm will handle it */
149        }
150       
151        return 0;
152}
153
154/* Start disconnection of a peer: send DPR */
155int fd_p_dp_initiate(struct fd_peer * peer, char * reason)
156{
157        struct msg * msg = NULL;
158        struct dict_object * dictobj = NULL;
159        struct avp * avp = NULL;
160        struct dict_enumval_request er;
161        union avp_value val;
162       
163        TRACE_ENTRY("%p %p", peer, reason);
164       
165        /* Create a new DWR instance */
166        CHECK_FCT( fd_msg_new ( fd_dict_cmd_DPR, MSGFL_ALLOC_ETEID, &msg ) );
167       
168        /* Add the Origin information */
169        CHECK_FCT( fd_msg_add_origin ( msg, 0 ) );
170       
171        /* Add the Disconnect-Cause */
172        CHECK_FCT( fd_msg_avp_new ( fd_dict_avp_DC, 0, &avp ) );
173       
174        /* Search the value in the dictionary */
175        memset(&er, 0, sizeof(er));
176        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, fd_dict_avp_DC, &er.type_obj, ENOENT )  );
177        er.search.enum_name = reason ?: "REBOOTING";
178        CHECK_FCT_DO( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &er, &dictobj, ENOENT ), { ASSERT(0); /* internal error: unknown reason */ }  );
179        CHECK_FCT( fd_dict_getval( dictobj, &er.search ) );
180       
181        /* Set the value in the AVP */
182        val.u32 = er.search.enum_value.u32;
183        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
184        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
185       
186        /* Save the value also in the peer */
187        peer->p_hdr.info.runtime.pir_lastDC = val.u32;
188       
189        /* Update the peer state and timer */
190        CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING) );
191        fd_psm_next_timeout(peer, 0, DPR_TIMEOUT);
192       
193        /* Now send the DPR message */
194        CHECK_FCT_DO( fd_out_send(&msg, NULL, peer, FD_CNX_ORDERED), /* ignore since we are on timeout anyway */ );
195       
196        return 0;
197}
Note: See TracBrowser for help on using the repository browser.