Navigation


source: freeDiameter/libfdcore/p_psm.c @ 691:78b665400097

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

Cleanup all pthread_cleanup_push / pop pairs so that pop is always called after push, or ASSERT(0) is some grave errors

File size: 24.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/* The actual declaration of peer_state_str */
39DECLARE_STATE_STR();
40
41/* Helper for next macro */
42#define case_str( _val )                \
43        case _val : return #_val
44
45DECLARE_PEV_STR();
46
47/************************************************************************/
48/*                      Delayed startup                                 */
49/************************************************************************/
50static int started = 0;
51static pthread_mutex_t  started_mtx = PTHREAD_MUTEX_INITIALIZER;
52static pthread_cond_t   started_cnd = PTHREAD_COND_INITIALIZER;
53
54/* Wait for start signal */
55static int fd_psm_waitstart()
56{
57        int ret = 0;
58        TRACE_ENTRY("");
59        CHECK_POSIX( pthread_mutex_lock(&started_mtx) );
60awake: 
61        if (!ret && !started) {
62                pthread_cleanup_push( fd_cleanup_mutex, &started_mtx );
63                CHECK_POSIX_DO( ret = pthread_cond_wait(&started_cnd, &started_mtx), );
64                pthread_cleanup_pop( 0 );
65                goto awake;
66        }
67        CHECK_POSIX( pthread_mutex_unlock(&started_mtx) );
68        return ret;
69}
70
71/* Allow the state machines to start */
72int fd_psm_start()
73{
74        TRACE_ENTRY("");
75        CHECK_POSIX( pthread_mutex_lock(&started_mtx) );
76        started = 1;
77        CHECK_POSIX( pthread_cond_broadcast(&started_cnd) );
78        CHECK_POSIX( pthread_mutex_unlock(&started_mtx) );
79        return 0;
80}
81
82
83/************************************************************************/
84/*                 Manage the list of active peers                      */
85/************************************************************************/
86
87/* Enter/leave OPEN state */
88static int enter_open_state(struct fd_peer * peer)
89{
90        struct fd_list * li;
91        CHECK_PARAMS( FD_IS_LIST_EMPTY(&peer->p_actives) );
92       
93        /* Callback registered by the credential validator (fd_peer_validate_register) */
94        if (peer->p_cb2) {
95                CHECK_FCT_DO( (*peer->p_cb2)(&peer->p_hdr.info),
96                        {
97                                TRACE_DEBUG(FULL, "Validation failed, terminating the connection");
98                                fd_psm_terminate(peer, "DO_NOT_WANT_TO_TALK_TO_YOU" );
99                        } );
100                peer->p_cb2 = NULL;
101                return 0;
102        }
103        /* Insert in the active peers list */
104        CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_activ_peers_rw) );
105        for (li = fd_g_activ_peers.next; li != &fd_g_activ_peers; li = li->next) {
106                struct fd_peer * next_p = (struct fd_peer *)li->o;
107                int cmp = strcmp(peer->p_hdr.info.pi_diamid, next_p->p_hdr.info.pi_diamid);
108                if (cmp < 0)
109                        break;
110        }
111        fd_list_insert_before(li, &peer->p_actives);
112        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_activ_peers_rw) );
113       
114        /* Callback registered when the peer was added, by fd_peer_add */
115        if (peer->p_cb) {
116                TRACE_DEBUG(FULL, "Calling add callback for peer %s", peer->p_hdr.info.pi_diamid);
117                (*peer->p_cb)(&peer->p_hdr.info, peer->p_cb_data);
118                peer->p_cb = NULL;
119                peer->p_cb_data = NULL;
120        }
121       
122        /* Start the thread to handle outgoing messages */
123        CHECK_FCT( fd_out_start(peer) );
124       
125        /* Update the expiry timer now */
126        CHECK_FCT( fd_p_expi_update(peer) );
127       
128        return 0;
129}
130static int leave_open_state(struct fd_peer * peer)
131{
132        /* Remove from active peers list */
133        CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_activ_peers_rw) );
134        fd_list_unlink( &peer->p_actives );
135        CHECK_POSIX( pthread_rwlock_unlock(&fd_g_activ_peers_rw) );
136       
137        /* Stop the "out" thread */
138        CHECK_FCT( fd_out_stop(peer) );
139       
140        /* Failover the messages */
141        fd_peer_failover_msg(peer);
142       
143        return 0;
144}
145
146
147/************************************************************************/
148/*                      Helpers for state changes                       */
149/************************************************************************/
150
151/* Cleanup pending events in the peer */
152void fd_psm_events_free(struct fd_peer * peer)
153{
154        struct fd_event * ev;
155        /* Purge all events, and free the associated data if any */
156        while (fd_fifo_tryget( peer->p_events, &ev ) == 0) {
157                switch (ev->code) {
158                        case FDEVP_CNX_ESTABLISHED: {
159                                fd_cnx_destroy(ev->data);
160                        }
161                        break;
162                       
163                        case FDEVP_TERMINATE:
164                                /* Do not free the string since it is a constant */
165                        break;
166                       
167                        case FDEVP_CNX_INCOMING: {
168                                struct cnx_incoming * evd = ev->data;
169                                fd_msg_log( FD_MSG_LOG_DROPPED, evd->cer, "Message discarded while cleaning peer state machine queue." );
170                                CHECK_FCT_DO( fd_msg_free(evd->cer), /* continue */);
171                                fd_cnx_destroy(evd->cnx);
172                        }
173                        default:
174                                free(ev->data);
175                }
176                free(ev);
177        }
178}
179
180
181/* Change state */
182int fd_psm_change_state(struct fd_peer * peer, int new_state)
183{
184        int old;
185       
186        TRACE_ENTRY("%p %d(%s)", peer, new_state, STATE_STR(new_state));
187        CHECK_PARAMS( CHECK_PEER(peer) );
188        fd_cpu_flush_cache();
189        old = peer->p_hdr.info.runtime.pir_state;
190        if (old == new_state)
191                return 0;
192       
193        TRACE_DEBUG(((old == STATE_OPEN) || (new_state == STATE_OPEN)) ? INFO : FULL, "'%s'\t-> '%s'\t'%s'",
194                        STATE_STR(old),
195                        STATE_STR(new_state),
196                        peer->p_hdr.info.pi_diamid);
197       
198        peer->p_hdr.info.runtime.pir_state = new_state;
199        fd_cpu_flush_cache();
200       
201        if (old == STATE_OPEN) {
202                CHECK_FCT( leave_open_state(peer) );
203        }
204       
205        if (new_state == STATE_OPEN) {
206                CHECK_FCT( enter_open_state(peer) );
207        }
208       
209        if (new_state == STATE_CLOSED) {
210                /* Purge event list */
211                fd_psm_events_free(peer);
212               
213                /* If the peer is not persistant, we destroy it */
214                if (peer->p_hdr.info.config.pic_flags.persist == PI_PRST_NONE) {
215                        CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) );
216                }
217        }
218       
219        return 0;
220}
221
222/* Set timeout timer of next event */
223void fd_psm_next_timeout(struct fd_peer * peer, int add_random, int delay)
224{
225        TRACE_DEBUG(FULL, "Peer timeout reset to %d seconds%s", delay, add_random ? " (+/- 2)" : "" );
226       
227        /* Initialize the timer */
228        CHECK_POSIX_DO(  clock_gettime( CLOCK_REALTIME,  &peer->p_psm_timer ), ASSERT(0) );
229       
230        if (add_random) {
231                if (delay > 2)
232                        delay -= 2;
233                else
234                        delay = 0;
235
236                /* Add a random value between 0 and 4sec */
237                peer->p_psm_timer.tv_sec += random() % 4;
238                peer->p_psm_timer.tv_nsec+= random() % 1000000000L;
239                if (peer->p_psm_timer.tv_nsec > 1000000000L) {
240                        peer->p_psm_timer.tv_nsec -= 1000000000L;
241                        peer->p_psm_timer.tv_sec ++;
242                }
243        }
244       
245        peer->p_psm_timer.tv_sec += delay;
246       
247#ifdef SLOW_PSM
248        /* temporary for debug */
249        peer->p_psm_timer.tv_sec += 10;
250#endif
251}
252
253/* Cleanup the peer */
254void fd_psm_cleanup(struct fd_peer * peer, int terminate)
255{
256        /* Move to CLOSED state: failover messages, stop OUT thread, unlink peer from active list */
257        fd_cpu_flush_cache();
258        if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) {
259                CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), /* continue */ );
260        }
261       
262        fd_p_cnx_abort(peer, terminate);
263       
264        fd_p_ce_clear_cnx(peer, NULL);
265       
266        if (peer->p_receiver) {
267                fd_cnx_destroy(peer->p_receiver);
268                peer->p_receiver = NULL;
269        }
270       
271        if (terminate) {
272                fd_psm_events_free(peer);
273                CHECK_FCT_DO( fd_fifo_del(&peer->p_events), /* continue */ );
274        }
275       
276}
277
278
279/************************************************************************/
280/*                      The PSM thread                                  */
281/************************************************************************/
282/* Cancelation cleanup : set ZOMBIE state in the peer */
283void cleanup_setstate(void * arg) 
284{
285        struct fd_peer * peer = (struct fd_peer *)arg;
286        CHECK_PARAMS_DO( CHECK_PEER(peer), return );
287        peer->p_hdr.info.runtime.pir_state = STATE_ZOMBIE;
288        fd_cpu_flush_cache();
289        return;
290}
291
292/* The state machine thread (controler) */
293static void * p_psm_th( void * arg )
294{
295        struct fd_peer * peer = (struct fd_peer *)arg;
296        int created_started = started ? 1 : 0;
297        int event;
298        size_t ev_sz;
299        void * ev_data;
300       
301        CHECK_PARAMS_DO( CHECK_PEER(peer), ASSERT(0) );
302       
303        pthread_cleanup_push( cleanup_setstate, arg );
304       
305        /* Set the thread name */
306        {
307                char buf[48];
308                sprintf(buf, "PSM/%.*s", (int)sizeof(buf) - 5, peer->p_hdr.info.pi_diamid);
309                fd_log_threadname ( buf );
310        }
311       
312        /* The state machine starts in CLOSED state */
313        peer->p_hdr.info.runtime.pir_state = STATE_CLOSED;
314
315        /* Wait that the PSM are authorized to start in the daemon */
316        CHECK_FCT_DO( fd_psm_waitstart(), goto psm_end );
317       
318        /* Initialize the timer */
319        if (peer->p_flags.pf_responder) {
320                fd_psm_next_timeout(peer, 0, INCNX_TIMEOUT);
321        } else {
322                fd_psm_next_timeout(peer, created_started, 0);
323        }
324       
325psm_loop:
326        /* Get next event */
327        TRACE_DEBUG(FULL, "'%s' in state '%s' waiting for next event.",
328                        peer->p_hdr.info.pi_diamid, STATE_STR(peer->p_hdr.info.runtime.pir_state));
329        CHECK_FCT_DO( fd_event_timedget(peer->p_events, &peer->p_psm_timer, FDEVP_PSM_TIMEOUT, &event, &ev_sz, &ev_data), goto psm_end );
330        TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p,%zd)\t'%s'",
331                        STATE_STR(peer->p_hdr.info.runtime.pir_state),
332                        fd_pev_str(event), ev_data, ev_sz,
333                        peer->p_hdr.info.pi_diamid);
334
335        /* Now, the action depends on the current state and the incoming event */
336
337        /* The following states are impossible */
338        ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_NEW );
339        ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE );
340        ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_OPEN_HANDSHAKE ); /* because it should exist only between two loops */
341
342        /* Purge invalid events */
343        if (!CHECK_PEVENT(event)) {
344                TRACE_DEBUG(INFO, "Invalid event received in PSM '%s' : %d", peer->p_hdr.info.pi_diamid, event);
345                goto psm_loop;
346        }
347
348        /* Handle the (easy) debug event now */
349        if (event == FDEVP_DUMP_ALL) {
350                fd_peer_dump(peer, ANNOYING);
351                goto psm_loop;
352        }
353
354        /* Requests to terminate the peer object */
355        if (event == FDEVP_TERMINATE) {
356                switch (peer->p_hdr.info.runtime.pir_state) {
357                        case STATE_OPEN:
358                        case STATE_REOPEN:
359                                /* We cannot just close the conenction, we have to send a DPR first */
360                                CHECK_FCT_DO( fd_p_dp_initiate(peer, ev_data), goto psm_end );
361                                goto psm_loop;
362                       
363                        /*     
364                        case STATE_CLOSING:
365                        case STATE_WAITCNXACK:
366                        case STATE_WAITCNXACK_ELEC:
367                        case STATE_WAITCEA:
368                        case STATE_SUSPECT:
369                        case STATE_CLOSED:
370                        */
371                        default:
372                                /* In these cases, we just cleanup the peer object (if needed) and terminate */
373                                goto psm_end;
374                }
375        }
376       
377        /* A message was received */
378        if (event == FDEVP_CNX_MSG_RECV) {
379                struct msg * msg = NULL;
380                struct msg_hdr * hdr;
381               
382                /* If the current state does not allow receiving messages, just drop it */
383                if (peer->p_hdr.info.runtime.pir_state == STATE_CLOSED) {
384                        TRACE_DEBUG(FULL, "Purging message in queue while in CLOSED state (%zdb)", ev_sz);
385                        free(ev_data);
386                        goto psm_loop;
387                }
388               
389                /* Parse the received buffer */
390                CHECK_FCT_DO( fd_msg_parse_buffer( (void *)&ev_data, ev_sz, &msg), 
391                        {
392                                fd_log_debug("Received invalid data from peer '%s', closing the connection\n", peer->p_hdr.info.pi_diamid);
393                                free(ev_data);
394                                CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL), goto psm_reset );
395                                goto psm_loop;
396                        } );
397               
398                /* Log incoming message */
399                fd_msg_log( FD_MSG_LOG_RECEIVED, msg, "Received %zdb from '%s'", ev_sz, peer->p_hdr.info.pi_diamid );
400       
401                /* Extract the header */
402                CHECK_FCT_DO( fd_msg_hdr(msg, &hdr), goto psm_end );
403               
404                /* If it is an answer, associate with the request or drop */
405                if (!(hdr->msg_flags & CMD_FLAG_REQUEST)) {
406                        struct msg * req;
407                        /* Search matching request (same hbhid) */
408                        CHECK_FCT_DO( fd_p_sr_fetch(&peer->p_sr, hdr->msg_hbhid, &req), goto psm_end );
409                        if (req == NULL) {
410                                fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Answer received with no corresponding sent request." );
411                                fd_msg_free(msg);
412                                goto psm_loop;
413                        }
414                       
415                        /* Associate */
416                        CHECK_FCT_DO( fd_msg_answ_associate( msg, req ), goto psm_end );
417                }
418               
419                /* Now handle non-link-local messages */
420                if (fd_msg_is_routable(msg)) {
421                        switch (peer->p_hdr.info.runtime.pir_state) {
422                                /* To maximize compatibility -- should not be a security issue here */
423                                case STATE_REOPEN:
424                                case STATE_SUSPECT:
425                                case STATE_CLOSING:
426                                        TRACE_DEBUG(FULL, "Accepted a message while not in OPEN state... ");
427                                /* The standard situation : */
428                                case STATE_OPEN:
429                                        /* We received a valid routable message, update the expiry timer */
430                                        CHECK_FCT_DO( fd_p_expi_update(peer), goto psm_end );
431
432                                        /* Set the message source and add the Route-Record */
433                                        CHECK_FCT_DO( fd_msg_source_set( msg, peer->p_hdr.info.pi_diamid, 1, fd_g_config->cnf_dict ), goto psm_end);
434
435                                        /* Requeue to the global incoming queue */
436                                        CHECK_FCT_DO(fd_fifo_post(fd_g_incoming, &msg), goto psm_end );
437
438                                        /* Update the peer timer (only in OPEN state) */
439                                        if ((peer->p_hdr.info.runtime.pir_state == STATE_OPEN) && (!peer->p_flags.pf_dw_pending)) {
440                                                fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw);
441                                        }
442                                        break;
443                                       
444                                /* In other states, we discard the message, it is either old or invalid to send it for the remote peer */
445                                case STATE_WAITCNXACK:
446                                case STATE_WAITCNXACK_ELEC:
447                                case STATE_WAITCEA:
448                                case STATE_CLOSED:
449                                default:
450                                        /* In such case, just discard the message */
451                                        fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Received from peer '%s' while connection was not in OPEN state.", peer->p_hdr.info.pi_diamid );
452                                        fd_msg_free(msg);
453                        }
454                        goto psm_loop;
455                }
456               
457                /* Link-local message: They must be understood by our dictionary, otherwise we return an error */
458                {
459                        int ret = fd_msg_parse_or_error( &msg );
460                        if (ret != EBADMSG) {
461                                CHECK_FCT_DO( ret, goto psm_end );
462                        } else {
463                                if (msg) {
464                                        /* Send the error back to the peer */
465                                        CHECK_FCT_DO( ret = fd_out_send(&msg, NULL, peer, FD_CNX_ORDERED),  );
466                                        if (msg) {
467                                                /* Only if an error occurred & the message was not saved / dumped */
468                                                fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Internal error: Problem while sending (%s)\n", strerror(ret) );
469                                                CHECK_FCT_DO( fd_msg_free(msg), goto psm_end);
470                                        }
471                                } else {
472                                        /* We received an invalid answer, let's disconnect */
473                                        CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL), goto psm_reset );
474                                }
475                                goto psm_loop;
476                        }
477                }
478               
479                /* Handle the LL message and update the expiry timer appropriately */
480                switch (hdr->msg_code) {
481                        case CC_CAPABILITIES_EXCHANGE:
482                                CHECK_FCT_DO( fd_p_ce_msgrcv(&msg, (hdr->msg_flags & CMD_FLAG_REQUEST), peer), goto psm_reset );
483                                break;
484                       
485                        case CC_DISCONNECT_PEER:
486                                CHECK_FCT_DO( fd_p_dp_handle(&msg, (hdr->msg_flags & CMD_FLAG_REQUEST), peer), goto psm_reset );
487                                if (peer->p_hdr.info.runtime.pir_state == STATE_CLOSING)
488                                        goto psm_end;
489                                break;
490                       
491                        case CC_DEVICE_WATCHDOG:
492                                CHECK_FCT_DO( fd_p_dw_handle(&msg, (hdr->msg_flags & CMD_FLAG_REQUEST), peer), goto psm_reset );
493                                break;
494                       
495                        default:
496                                /* Unknown / unexpected / invalid message */
497                                TRACE_DEBUG(INFO, "Invalid non-routable command received: %u.", hdr->msg_code);
498                                if (hdr->msg_flags & CMD_FLAG_REQUEST) {
499                                        do {
500                                                /* Reply with an error code */
501                                                CHECK_FCT_DO( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &msg, MSGFL_ANSW_ERROR ), break );
502
503                                                /* Set the error code */
504                                                CHECK_FCT_DO( fd_msg_rescode_set(msg, "DIAMETER_INVALID_HDR_BITS", NULL, NULL, 1 ), break );
505
506                                                /* Send the answer */
507                                                CHECK_FCT_DO( fd_out_send(&msg, peer->p_cnxctx, peer, FD_CNX_ORDERED), break );
508                                        } while (0);
509                                } else {
510                                        /* We did ASK for it ??? */
511                                        fd_log_debug("Invalid PXY flag in answer header ?\n");
512                                }
513                               
514                                /* Cleanup the message if not done */
515                                if (msg) {
516                                        fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Received un-handled non-routable command from peer '%s'.", peer->p_hdr.info.pi_diamid );
517                                        CHECK_FCT_DO( fd_msg_free(msg), /* continue */);
518                                        msg = NULL;
519                                }
520                };
521               
522                /* At this point the message must have been fully handled already */
523                if (msg) {
524                        fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Internal error: unhandled message.", peer->p_hdr.info.pi_diamid );
525                        fd_msg_free(msg);
526                }
527               
528                goto psm_loop;
529        }
530       
531        /* The connection object is broken */
532        if (event == FDEVP_CNX_ERROR) {
533                switch (peer->p_hdr.info.runtime.pir_state) {
534                        case STATE_WAITCNXACK_ELEC:
535                                /* Abort the initiating side */
536                                fd_p_cnx_abort(peer, 0);
537                                /* Process the receiver side */
538                                CHECK_FCT_DO( fd_p_ce_process_receiver(peer), goto psm_end );
539                                break;
540                       
541                        case STATE_WAITCEA:
542                        case STATE_OPEN:
543                        case STATE_REOPEN:
544                        case STATE_WAITCNXACK:
545                        case STATE_SUSPECT:
546                        default:
547                                /* Mark the connection problem */
548                                peer->p_flags.pf_cnx_pb = 1;
549                               
550                                /* Destroy the connection, restart the timer to a new connection attempt */
551                                fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc);
552                               
553                        case STATE_CLOSED:
554                                goto psm_reset;
555                               
556                        case STATE_CLOSING:
557                                /* We sent a DPR so we are terminating, do not wait for DPA */
558                                goto psm_end;
559                               
560                }
561                goto psm_loop;
562        }
563       
564        /* The connection notified a change in endpoints */
565        if (event == FDEVP_CNX_EP_CHANGE) {
566                /* We actually don't care if we are in OPEN state here... */
567               
568                /* Cleanup the remote LL and primary addresses */
569                CHECK_FCT_DO( fd_ep_filter( &peer->p_hdr.info.pi_endpoints, EP_FL_CONF | EP_FL_DISC | EP_FL_ADV ), /* ignore the error */);
570                CHECK_FCT_DO( fd_ep_clearflags( &peer->p_hdr.info.pi_endpoints, EP_FL_PRIMARY ), /* ignore the error */);
571               
572                /* Get the new ones */
573                CHECK_FCT_DO( fd_cnx_getremoteeps(peer->p_cnxctx, &peer->p_hdr.info.pi_endpoints), /* ignore the error */);
574               
575                /* We do not support local endpoints change currently, but it could be added here if needed (refresh fd_g_config->cnf_endpoints)*/
576               
577                if (TRACE_BOOL(ANNOYING)) {
578                        TRACE_DEBUG(ANNOYING, "New remote endpoint(s):" );
579                        fd_ep_dump(6, &peer->p_hdr.info.pi_endpoints);
580                }
581               
582                /* Done */
583                goto psm_loop;
584        }
585       
586        /* A new connection was established and CER containing this peer id was received */
587        if (event == FDEVP_CNX_INCOMING) {
588                struct cnx_incoming * params = ev_data;
589                ASSERT(params);
590               
591                /* Handle the message */
592                CHECK_FCT_DO( fd_p_ce_handle_newCER(&params->cer, peer, &params->cnx, params->validate), goto psm_end );
593               
594                /* Cleanup if needed */
595                if (params->cnx) {
596                        fd_cnx_destroy(params->cnx);
597                        params->cnx = NULL;
598                }
599                if (params->cer) {
600                        fd_msg_log( FD_MSG_LOG_DROPPED, params->cer, "Internal error: this CER was not handled as expected." );
601                        CHECK_FCT_DO( fd_msg_free(params->cer), );
602                        params->cer = NULL;
603                }
604               
605                /* Loop */
606                free(ev_data);
607                goto psm_loop;
608        }
609       
610        /* A new connection has been established with the remote peer */
611        if (event == FDEVP_CNX_ESTABLISHED) {
612                struct cnxctx * cnx = ev_data;
613               
614                /* Release the resources of the connecting thread */
615                CHECK_POSIX_DO( pthread_join( peer->p_ini_thr, NULL), /* ignore, it is not a big deal */);
616                peer->p_ini_thr = (pthread_t)NULL;
617               
618                switch (peer->p_hdr.info.runtime.pir_state) {
619                        case STATE_WAITCNXACK_ELEC:
620                        case STATE_WAITCNXACK:
621                                fd_p_ce_handle_newcnx(peer, cnx);
622                                break;
623                               
624                        default:
625                                /* Just abort the attempt and continue */
626                                TRACE_DEBUG(FULL, "Connection attempt successful but current state is %s, closing...", STATE_STR(peer->p_hdr.info.runtime.pir_state));
627                                fd_cnx_destroy(cnx);
628                }
629               
630                goto psm_loop;
631        }
632       
633        /* A new connection has not been established with the remote peer */
634        if (event == FDEVP_CNX_FAILED) {
635               
636                /* Release the resources of the connecting thread */
637                CHECK_POSIX_DO( pthread_join( peer->p_ini_thr, NULL), /* ignore, it is not a big deal */);
638                peer->p_ini_thr = (pthread_t)NULL;
639               
640                switch (peer->p_hdr.info.runtime.pir_state) {
641                        case STATE_WAITCNXACK_ELEC:
642                                /* Abort the initiating side */
643                                fd_p_cnx_abort(peer, 0);
644                                /* Process the receiver side */
645                                CHECK_FCT_DO( fd_p_ce_process_receiver(peer), goto psm_end );
646                                break;
647                               
648                        case STATE_WAITCNXACK:
649                                /* Go back to CLOSE */
650                                fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc);
651                                goto psm_reset;
652                               
653                        default:
654                                /* Just ignore */
655                                TRACE_DEBUG(FULL, "Connection attempt failed but current state is %s, ignoring...", STATE_STR(peer->p_hdr.info.runtime.pir_state));
656                }
657               
658                goto psm_loop;
659        }
660       
661        /* The timeout for the current state has been reached */
662        if (event == FDEVP_PSM_TIMEOUT) {
663                switch (peer->p_hdr.info.runtime.pir_state) {
664                        case STATE_OPEN:
665                        case STATE_REOPEN:
666                                CHECK_FCT_DO( fd_p_dw_timeout(peer), goto psm_end );
667                                goto psm_loop;
668                               
669                        case STATE_CLOSED:
670                                CHECK_FCT_DO( fd_psm_change_state(peer, STATE_WAITCNXACK), goto psm_end );
671                                fd_psm_next_timeout(peer, 0, CNX_TIMEOUT);
672                                CHECK_FCT_DO( fd_p_cnx_init(peer), goto psm_end );
673                                goto psm_loop;
674                               
675                        case STATE_SUSPECT:
676                                /* Mark the connection problem */
677                                peer->p_flags.pf_cnx_pb = 1;
678                               
679                        case STATE_CLOSING:
680                        case STATE_WAITCNXACK:
681                        case STATE_WAITCEA:
682                                /* Destroy the connection, restart the timer to a new connection attempt */
683                                fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc);
684                                goto psm_reset;
685                               
686                        case STATE_WAITCNXACK_ELEC:
687                                /* Abort the initiating side */
688                                fd_p_cnx_abort(peer, 0);
689                                /* Process the receiver side */
690                                CHECK_FCT_DO( fd_p_ce_process_receiver(peer), goto psm_end );
691                                goto psm_loop;
692                       
693                        default:
694                                ASSERT(0); /* implementation problem, we did not foresee this case? */
695                }
696        }
697       
698        /* Default action : the handling has not yet been implemented. [for debug only] */
699        TRACE_DEBUG(INFO, "Missing handler in PSM for '%s'\t<-- '%s'", STATE_STR(peer->p_hdr.info.runtime.pir_state), fd_pev_str(event));
700psm_reset:
701        if (peer->p_flags.pf_delete)
702                goto psm_end;
703        fd_psm_cleanup(peer, 0);
704        goto psm_loop;
705       
706psm_end:
707        fd_psm_cleanup(peer, 1);
708        TRACE_DEBUG(INFO, "'%s'\t-> STATE_ZOMBIE (terminated)\t'%s'",
709                        STATE_STR(peer->p_hdr.info.runtime.pir_state),
710                        peer->p_hdr.info.pi_diamid);
711        pthread_cleanup_pop(1); /* set STATE_ZOMBIE */
712        fd_cpu_flush_cache();
713        peer->p_psm = (pthread_t)NULL;
714        pthread_detach(pthread_self());
715        return NULL;
716}
717
718
719/************************************************************************/
720/*                      Functions to control the PSM                    */
721/************************************************************************/
722/* Create the PSM thread of one peer structure */
723int fd_psm_begin(struct fd_peer * peer )
724{
725        TRACE_ENTRY("%p", peer);
726       
727        /* Check the peer and state are OK */
728        CHECK_PARAMS( CHECK_PEER(peer) && (peer->p_hdr.info.runtime.pir_state == STATE_NEW) );
729       
730        /* Create the FIFO for events */
731        CHECK_FCT( fd_fifo_new(&peer->p_events) );
732       
733        /* Create the PSM controler thread */
734        CHECK_POSIX( pthread_create( &peer->p_psm, NULL, p_psm_th, peer ) );
735       
736        /* We're done */
737        return 0;
738}
739
740/* End the PSM (clean ending) */
741int fd_psm_terminate(struct fd_peer * peer, char * reason )
742{
743        TRACE_ENTRY("%p", peer);
744        CHECK_PARAMS( CHECK_PEER(peer) );
745       
746        fd_cpu_flush_cache();
747        if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) {
748                CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, reason) );
749        } else {
750                TRACE_DEBUG(FULL, "Peer '%s' was already terminated", peer->p_hdr.info.pi_diamid);
751        }
752        return 0;
753}
754
755/* End the PSM & cleanup the peer structure */
756void fd_psm_abord(struct fd_peer * peer )
757{
758        TRACE_ENTRY("%p", peer);
759       
760        /* Cancel PSM thread */
761        CHECK_FCT_DO( fd_thr_term(&peer->p_psm), /* continue */ );
762       
763        /* Cleanup the data */
764        fd_psm_cleanup(peer, 1);
765       
766        /* Destroy the event list */
767        CHECK_FCT_DO( fd_fifo_del(&peer->p_events), /* continue */ );
768       
769        /* Remaining cleanups are performed in fd_peer_free */
770        return;
771}
772
Note: See TracBrowser for help on using the repository browser.