Navigation


source: freeDiameter/freeDiameter/p_psm.c @ 29:5ba91682f0bc

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

Added a test for cnxctx (tbc) and fixed some bugs

File size: 9.2 KB
Line 
1/*********************************************************************************************************
2* Software License Agreement (BSD License)                                                               *
3* Author: Sebastien Decugis <sdecugis@nict.go.jp>                                                        *
4*                                                                                                        *
5* Copyright (c) 2009, 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 "fD.h"
37
38const char *peer_state_str[] = { 
39          "STATE_NEW"
40        , "STATE_OPEN"
41        , "STATE_CLOSED"
42        , "STATE_CLOSING"
43        , "STATE_WAITCNXACK"
44        , "STATE_WAITCNXACK_ELEC"
45        , "STATE_WAITCEA"
46        , "STATE_OPEN_HANDSHAKE"
47        , "STATE_SUSPECT"
48        , "STATE_REOPEN"
49        , "STATE_ZOMBIE"
50        };
51
52const char * fd_pev_str(int event)
53{
54        switch (event) {
55        #define case_str( _val )\
56                case _val : return #_val
57                case_str(FDEVP_DUMP_ALL);
58                case_str(FDEVP_TERMINATE);
59                case_str(FDEVP_CNX_MSG_RECV);
60                case_str(FDEVP_CNX_ERROR);
61                case_str(FDEVP_CNX_EP_CHANGE);
62                case_str(FDEVP_CNX_INCOMING);
63                case_str(FDEVP_PSM_TIMEOUT);
64               
65                default:
66                        TRACE_DEBUG(FULL, "Unknown event : %d", event);
67                        return "Unknown event";
68        }
69}
70
71
72static int started = 0;
73static pthread_mutex_t  started_mtx = PTHREAD_MUTEX_INITIALIZER;
74static pthread_cond_t   started_cnd = PTHREAD_COND_INITIALIZER;
75
76/* Wait for start signal */
77static int fd_psm_waitstart()
78{
79        TRACE_ENTRY("");
80        CHECK_POSIX( pthread_mutex_lock(&started_mtx) );
81awake: 
82        if (! started) {
83                pthread_cleanup_push( fd_cleanup_mutex, &started_mtx );
84                CHECK_POSIX( pthread_cond_wait(&started_cnd, &started_mtx) );
85                pthread_cleanup_pop( 0 );
86                goto awake;
87        }
88        CHECK_POSIX( pthread_mutex_unlock(&started_mtx) );
89        return 0;
90}
91
92/* Cancelation cleanup : set ZOMBIE state in the peer */
93void cleanup_state(void * arg) 
94{
95        struct fd_peer * peer = (struct fd_peer *)arg;
96        CHECK_PARAMS_DO( CHECK_PEER(peer), return );
97        peer->p_hdr.info.pi_state = STATE_ZOMBIE;
98        return;
99}
100
101/* Set timeout timer of next event */
102static void psm_next_timeout(struct fd_peer * peer, int add_random, int delay)
103{
104        /* Initialize the timer */
105        CHECK_POSIX_DO(  clock_gettime( CLOCK_REALTIME,  &peer->p_psm_timer ), ASSERT(0) );
106       
107        if (add_random) {
108                if (delay > 2)
109                        delay -= 2;
110                else
111                        delay = 0;
112
113                /* Add a random value between 0 and 4sec */
114                peer->p_psm_timer.tv_sec += random() % 4;
115                peer->p_psm_timer.tv_nsec+= random() % 1000000000L;
116                if (peer->p_psm_timer.tv_nsec > 1000000000L) {
117                        peer->p_psm_timer.tv_nsec -= 1000000000L;
118                        peer->p_psm_timer.tv_sec ++;
119                }
120        }
121       
122        peer->p_psm_timer.tv_sec += delay;
123       
124#if 0
125        /* temporary for debug */
126        peer->p_psm_timer.tv_sec += 10;
127#endif
128}
129
130/* The state machine thread (controler) */
131static void * p_psm_th( void * arg )
132{
133        struct fd_peer * peer = (struct fd_peer *)arg;
134        int created_started = started;
135        int event;
136        size_t ev_sz;
137        void * ev_data;
138       
139        CHECK_PARAMS_DO( CHECK_PEER(peer), ASSERT(0) );
140       
141        pthread_cleanup_push( cleanup_state, arg );
142       
143        /* Set the thread name */
144        {
145                char buf[48];
146                sprintf(buf, "PSM/%.*s", sizeof(buf) - 5, peer->p_hdr.info.pi_diamid);
147                fd_log_threadname ( buf );
148        }
149       
150        /* The state machine starts in CLOSED state */
151        peer->p_hdr.info.pi_state = STATE_CLOSED;
152       
153        /* Wait that the PSM are authorized to start in the daemon */
154        CHECK_FCT_DO( fd_psm_waitstart(), goto psm_end );
155       
156        /* Initialize the timer */
157        if (peer->p_flags.pf_responder) {
158                psm_next_timeout(peer, 0, INCNX_TIMEOUT);
159        } else {
160                psm_next_timeout(peer, created_started ? 0 : 1, 0);
161        }
162       
163psm_loop:
164        /* Get next event */
165        CHECK_FCT_DO( fd_event_timedget(peer->p_events, &peer->p_psm_timer, FDEVP_PSM_TIMEOUT, &event, &ev_sz, &ev_data), goto psm_end );
166        TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p,%zd)\t'%s'",
167                        STATE_STR(peer->p_hdr.info.pi_state),
168                        fd_pev_str(event), ev_data, ev_sz,
169                        peer->p_hdr.info.pi_diamid);
170
171        /* Now, the action depends on the current state and the incoming event */
172
173        /* The following two states are impossible */
174        ASSERT( peer->p_hdr.info.pi_state != STATE_NEW );
175        ASSERT( peer->p_hdr.info.pi_state != STATE_ZOMBIE );
176
177        /* Purge invalid events */
178        if (!CHECK_EVENT(event)) {
179                TRACE_DEBUG(INFO, "Invalid event received in PSM '%s' : %d", peer->p_hdr.info.pi_diamid, event);
180                goto psm_loop;
181        }
182
183        /* Handle the (easy) debug event now */
184        if (event == FDEVP_DUMP_ALL) {
185                fd_peer_dump(peer, ANNOYING);
186                goto psm_loop;
187        }
188
189        /* Requests to terminate the peer object */
190        if (event == FDEVP_TERMINATE) {
191                switch (peer->p_hdr.info.pi_state) {
192                        case STATE_CLOSING:
193                        case STATE_WAITCNXACK:
194                        case STATE_WAITCNXACK_ELEC:
195                        case STATE_WAITCEA:
196                        case STATE_SUSPECT:
197                                /* In these cases, we just cleanup the peer object and terminate now */
198                                TODO("Cleanup the PSM: terminate connection object, ...");
199                        case STATE_CLOSED:
200                                /* Then we just terminate the PSM */
201                                goto psm_end;
202                               
203                        case STATE_OPEN:
204                        case STATE_REOPEN:
205                                /* We cannot just close the conenction, we have to send a DPR first */
206                                TODO("Send DPR, mark the peer as CLOSING");
207                                goto psm_loop;
208                }
209        }
210       
211        /* A new connection was established and CER containing this peer id was received */
212        if (event == FDEVP_CNX_INCOMING) {
213                struct cnx_incoming * params = ev_data;
214                ASSERT(params);
215               
216                switch (peer->p_hdr.info.pi_state) {
217                        case STATE_CLOSED:
218                                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");
219                                break;
220                               
221                        case STATE_WAITCNXACK:
222                        case STATE_WAITCEA:
223                                TODO("Election");
224                                break;
225                               
226                        default:
227                                TODO("Reply with error CEA");
228                                TODO("Close the connection");
229                                /* reject_incoming_connection */
230                       
231                }
232               
233                free(ev_data);
234                goto psm_loop;
235        }
236       
237        /* MSG_RECEIVED: fd_p_expi_update(struct fd_peer * peer ) */
238        /* If timeout or OPEN : call cb if defined */
239
240        /* Default action : the handling has not yet been implemented. */
241        TODO("Missing handler in PSM : '%s'\t<-- '%s'", STATE_STR(peer->p_hdr.info.pi_state), fd_pev_str(event));
242        if (event == FDEVP_PSM_TIMEOUT) {
243                /* We have not handled timeout in this state, let's postpone next alert */
244                psm_next_timeout(peer, 0, 60);
245        }
246       
247        goto psm_loop;
248       
249psm_end:
250        pthread_cleanup_pop(1); /* set STATE_ZOMBIE */
251        peer->p_psm = (pthread_t)NULL;
252        pthread_detach(pthread_self());
253        return NULL;
254}       
255
256/* Create the PSM thread of one peer structure */
257int fd_psm_begin(struct fd_peer * peer )
258{
259        TRACE_ENTRY("%p", peer);
260       
261        /* Check the peer and state are OK */
262        CHECK_PARAMS( CHECK_PEER(peer) && (peer->p_hdr.info.pi_state == STATE_NEW) );
263       
264        /* Create the PSM controler thread */
265        CHECK_POSIX( pthread_create( &peer->p_psm, NULL, p_psm_th, peer ) );
266       
267        /* We're done */
268        return 0;
269}
270
271/* End the PSM (clean ending) */
272int fd_psm_terminate(struct fd_peer * peer )
273{
274        TRACE_ENTRY("%p", peer);
275        CHECK_PARAMS( CHECK_PEER(peer) );
276       
277        if (peer->p_hdr.info.pi_state != STATE_ZOMBIE) {
278                CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) );
279        } else {
280                TRACE_DEBUG(FULL, "Peer '%s' was already terminated", peer->p_hdr.info.pi_diamid);
281        }
282        return 0;
283}
284
285/* End the PSM violently */
286void fd_psm_abord(struct fd_peer * peer )
287{
288        TRACE_ENTRY("%p", peer);
289        TODO("Cancel PSM thread");
290        TODO("Cancel IN thread");
291        TODO("Cancel OUT thread");
292        TODO("Cleanup the peer connection object");
293        TODO("Cleanup the message queues (requeue)");
294        return;
295}
296
297/* Allow the state machines to start */
298int fd_psm_start()
299{
300        TRACE_ENTRY("");
301        CHECK_POSIX( pthread_mutex_lock(&started_mtx) );
302        started = 1;
303        CHECK_POSIX( pthread_cond_broadcast(&started_cnd) );
304        CHECK_POSIX( pthread_mutex_unlock(&started_mtx) );
305        return 0;
306}
307
Note: See TracBrowser for help on using the repository browser.