comparison freeDiameter/p_psm.c @ 37:cc3c59fe98fe

Lot of cleanups in peer structure management
author Sebastien Decugis <sdecugis@nict.go.jp>
date Thu, 05 Nov 2009 14:28:46 +0900
parents 1498b3c7304c
children 68c1890f7049
comparison
equal deleted inserted replaced
36:1498b3c7304c 37:cc3c59fe98fe
92 /* Callback registered by the credential validator (fd_peer_validate_register) */ 92 /* Callback registered by the credential validator (fd_peer_validate_register) */
93 if (peer->p_cb2) { 93 if (peer->p_cb2) {
94 CHECK_FCT_DO( (*peer->p_cb2)(&peer->p_hdr.info), 94 CHECK_FCT_DO( (*peer->p_cb2)(&peer->p_hdr.info),
95 { 95 {
96 TRACE_DEBUG(FULL, "Validation failed, moving to state CLOSING"); 96 TRACE_DEBUG(FULL, "Validation failed, moving to state CLOSING");
97 peer->p_hdr.info.pi_state = STATE_CLOSING; 97 peer->p_hdr.info.runtime.pir_state = STATE_CLOSING;
98 fd_psm_terminate(peer); 98 fd_psm_terminate(peer);
99 } ); 99 } );
100 peer->p_cb2 = NULL; 100 peer->p_cb2 = NULL;
101 return 0; 101 return 0;
102 } 102 }
120 } 120 }
121 121
122 /* Start the thread to handle outgoing messages */ 122 /* Start the thread to handle outgoing messages */
123 CHECK_FCT( fd_out_start(peer) ); 123 CHECK_FCT( fd_out_start(peer) );
124 124
125 /* Update the expiry timer now */
126 CHECK_FCT( fd_p_expi_update(peer) );
127
125 return 0; 128 return 0;
126 } 129 }
127 static int leave_open_state(struct fd_peer * peer) 130 static int leave_open_state(struct fd_peer * peer)
128 { 131 {
129 /* Remove from active peers list */ 132 /* Remove from active peers list */
142 145
143 146
144 /************************************************************************/ 147 /************************************************************************/
145 /* Helpers for state changes */ 148 /* Helpers for state changes */
146 /************************************************************************/ 149 /************************************************************************/
150
151 /* Cleanup pending events in the peer */
152 void 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_CNX_INCOMING: {
164 struct cnx_incoming * evd = ev->data;
165 CHECK_FCT_DO( fd_msg_free(evd->cer), /* continue */);
166 fd_cnx_destroy(evd->cnx);
167 }
168 default:
169 free(ev->data);
170 }
171 free(ev);
172 }
173 }
174
175
147 /* Change state */ 176 /* Change state */
148 int fd_psm_change_state(struct fd_peer * peer, int new_state) 177 int fd_psm_change_state(struct fd_peer * peer, int new_state)
149 { 178 {
150 int old; 179 int old;
151 180
152 TRACE_ENTRY("%p %d(%s)", peer, new_state, STATE_STR(new_state)); 181 TRACE_ENTRY("%p %d(%s)", peer, new_state, STATE_STR(new_state));
153 CHECK_PARAMS( CHECK_PEER(peer) ); 182 CHECK_PARAMS( CHECK_PEER(peer) );
154 old = peer->p_hdr.info.pi_state; 183 old = peer->p_hdr.info.runtime.pir_state;
155 if (old == new_state) 184 if (old == new_state)
156 return 0; 185 return 0;
157 186
158 TRACE_DEBUG(FULL, "'%s'\t-> '%s'\t'%s'", 187 TRACE_DEBUG(FULL, "'%s'\t-> '%s'\t'%s'",
159 STATE_STR(old), 188 STATE_STR(old),
162 191
163 if (old == STATE_OPEN) { 192 if (old == STATE_OPEN) {
164 CHECK_FCT( leave_open_state(peer) ); 193 CHECK_FCT( leave_open_state(peer) );
165 } 194 }
166 195
167 peer->p_hdr.info.pi_state = new_state; 196 peer->p_hdr.info.runtime.pir_state = new_state;
168 197
169 if (new_state == STATE_OPEN) { 198 if (new_state == STATE_OPEN) {
170 CHECK_FCT( enter_open_state(peer) ); 199 CHECK_FCT( enter_open_state(peer) );
171 } 200 }
172 201
173 if ((new_state == STATE_CLOSED) && (peer->p_hdr.info.pi_flags.persist == PI_PRST_NONE)) { 202 if (new_state == STATE_CLOSED) {
174 CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) ); 203 /* Purge event list */
204 fd_psm_events_free(peer);
205
206 /* If the peer is not persistant, we destroy it */
207 if (peer->p_hdr.info.config.pic_flags.persist == PI_PRST_NONE) {
208 CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) );
209 }
175 } 210 }
176 211
177 return 0; 212 return 0;
178 } 213 }
179 214
207 } 242 }
208 243
209 /* Cleanup the peer */ 244 /* Cleanup the peer */
210 void fd_psm_cleanup(struct fd_peer * peer) 245 void fd_psm_cleanup(struct fd_peer * peer)
211 { 246 {
212 /* Move to CLOSED state */ 247 /* Move to CLOSED state: failover messages, stop OUT thread, unlink peer from active list */
213 CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), /* continue */ ); 248 CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), /* continue */ );
214 249
215 /* Destroy the connection */ 250 /* Destroy data */
251 CHECK_FCT_DO( fd_thr_term(&peer->p_ini_thr), /* continue */);
216 if (peer->p_cnxctx) { 252 if (peer->p_cnxctx) {
217 fd_cnx_destroy(peer->p_cnxctx); 253 fd_cnx_destroy(peer->p_cnxctx);
218 peer->p_cnxctx = NULL; 254 peer->p_cnxctx = NULL;
219 } 255 }
220 256 if (peer->p_initiator) {
221 /* What else ? */ 257 fd_cnx_destroy(peer->p_initiator);
222 TODO("..."); 258 peer->p_initiator = NULL;
259 }
260 if (peer->p_receiver) {
261 fd_cnx_destroy(peer->p_receiver);
262 peer->p_receiver = NULL;
263 }
223 264
224 } 265 }
225 266
226 267
227 /************************************************************************/ 268 /************************************************************************/
230 /* Cancelation cleanup : set ZOMBIE state in the peer */ 271 /* Cancelation cleanup : set ZOMBIE state in the peer */
231 void cleanup_setstate(void * arg) 272 void cleanup_setstate(void * arg)
232 { 273 {
233 struct fd_peer * peer = (struct fd_peer *)arg; 274 struct fd_peer * peer = (struct fd_peer *)arg;
234 CHECK_PARAMS_DO( CHECK_PEER(peer), return ); 275 CHECK_PARAMS_DO( CHECK_PEER(peer), return );
235 peer->p_hdr.info.pi_state = STATE_ZOMBIE; 276 peer->p_hdr.info.runtime.pir_state = STATE_ZOMBIE;
236 return; 277 return;
237 } 278 }
238 279
239 /* The state machine thread (controler) */ 280 /* The state machine thread (controler) */
240 static void * p_psm_th( void * arg ) 281 static void * p_psm_th( void * arg )
255 sprintf(buf, "PSM/%.*s", sizeof(buf) - 5, peer->p_hdr.info.pi_diamid); 296 sprintf(buf, "PSM/%.*s", sizeof(buf) - 5, peer->p_hdr.info.pi_diamid);
256 fd_log_threadname ( buf ); 297 fd_log_threadname ( buf );
257 } 298 }
258 299
259 /* The state machine starts in CLOSED state */ 300 /* The state machine starts in CLOSED state */
260 peer->p_hdr.info.pi_state = STATE_CLOSED; 301 peer->p_hdr.info.runtime.pir_state = STATE_CLOSED;
261 302
262 /* Wait that the PSM are authorized to start in the daemon */ 303 /* Wait that the PSM are authorized to start in the daemon */
263 CHECK_FCT_DO( fd_psm_waitstart(), goto psm_end ); 304 CHECK_FCT_DO( fd_psm_waitstart(), goto psm_end );
264 305
265 /* Initialize the timer */ 306 /* Initialize the timer */
271 312
272 psm_loop: 313 psm_loop:
273 /* Get next event */ 314 /* Get next event */
274 CHECK_FCT_DO( fd_event_timedget(peer->p_events, &peer->p_psm_timer, FDEVP_PSM_TIMEOUT, &event, &ev_sz, &ev_data), goto psm_end ); 315 CHECK_FCT_DO( fd_event_timedget(peer->p_events, &peer->p_psm_timer, FDEVP_PSM_TIMEOUT, &event, &ev_sz, &ev_data), goto psm_end );
275 TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p,%zd)\t'%s'", 316 TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p,%zd)\t'%s'",
276 STATE_STR(peer->p_hdr.info.pi_state), 317 STATE_STR(peer->p_hdr.info.runtime.pir_state),
277 fd_pev_str(event), ev_data, ev_sz, 318 fd_pev_str(event), ev_data, ev_sz,
278 peer->p_hdr.info.pi_diamid); 319 peer->p_hdr.info.pi_diamid);
279 320
280 /* Now, the action depends on the current state and the incoming event */ 321 /* Now, the action depends on the current state and the incoming event */
281 322
282 /* The following states are impossible */ 323 /* The following states are impossible */
283 ASSERT( peer->p_hdr.info.pi_state != STATE_NEW ); 324 ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_NEW );
284 ASSERT( peer->p_hdr.info.pi_state != STATE_ZOMBIE ); 325 ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE );
285 ASSERT( peer->p_hdr.info.pi_state != STATE_OPEN_HANDSHAKE ); /* because it exists only between two loops */ 326 ASSERT( peer->p_hdr.info.runtime.pir_state != STATE_OPEN_HANDSHAKE ); /* because it exists only between two loops */
286 327
287 /* Purge invalid events */ 328 /* Purge invalid events */
288 if (!CHECK_PEVENT(event)) { 329 if (!CHECK_PEVENT(event)) {
289 TRACE_DEBUG(INFO, "Invalid event received in PSM '%s' : %d", peer->p_hdr.info.pi_diamid, event); 330 TRACE_DEBUG(INFO, "Invalid event received in PSM '%s' : %d", peer->p_hdr.info.pi_diamid, event);
290 goto psm_loop; 331 goto psm_loop;
296 goto psm_loop; 337 goto psm_loop;
297 } 338 }
298 339
299 /* Requests to terminate the peer object */ 340 /* Requests to terminate the peer object */
300 if (event == FDEVP_TERMINATE) { 341 if (event == FDEVP_TERMINATE) {
301 switch (peer->p_hdr.info.pi_state) { 342 switch (peer->p_hdr.info.runtime.pir_state) {
302 case STATE_OPEN: 343 case STATE_OPEN:
303 case STATE_REOPEN: 344 case STATE_REOPEN:
304 /* We cannot just close the conenction, we have to send a DPR first */ 345 /* We cannot just close the conenction, we have to send a DPR first */
305 CHECK_FCT_DO( fd_p_dp_initiate(peer), goto psm_end ); 346 CHECK_FCT_DO( fd_p_dp_initiate(peer), goto psm_end );
306 goto psm_loop; 347 goto psm_loop;
322 /* A message was received */ 363 /* A message was received */
323 if (event == FDEVP_CNX_MSG_RECV) { 364 if (event == FDEVP_CNX_MSG_RECV) {
324 struct msg * msg = NULL; 365 struct msg * msg = NULL;
325 struct msg_hdr * hdr; 366 struct msg_hdr * hdr;
326 367
368 /* If the current state does not allow receiving messages, just drop it */
369 if (peer->p_hdr.info.runtime.pir_state == STATE_CLOSED) {
370 TRACE_DEBUG(FULL, "Purging message in queue while in CLOSED state (%zdb)", ev_sz);
371 free(ev_data);
372 goto psm_loop;
373 }
374
327 /* Parse the received buffer */ 375 /* Parse the received buffer */
328 CHECK_FCT_DO( fd_msg_parse_buffer( (void *)&ev_data, ev_sz, &msg), 376 CHECK_FCT_DO( fd_msg_parse_buffer( (void *)&ev_data, ev_sz, &msg),
329 { 377 {
330 fd_log_debug("Received invalid data from peer '%s', closing the connection\n", peer->p_hdr.info.pi_diamid); 378 fd_log_debug("Received invalid data from peer '%s', closing the connection\n", peer->p_hdr.info.pi_diamid);
331 CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL), goto psm_end ); 379 CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL), goto psm_end );
336 fd_msg_dump_walk(FULL + 1, msg); 384 fd_msg_dump_walk(FULL + 1, msg);
337 385
338 /* Extract the header */ 386 /* Extract the header */
339 CHECK_FCT_DO( fd_msg_hdr(msg, &hdr), goto psm_end ); 387 CHECK_FCT_DO( fd_msg_hdr(msg, &hdr), goto psm_end );
340 388
341 /* If it is an answer, associate with the request */ 389 /* If it is an answer, associate with the request or drop */
342 if (!(hdr->msg_flags & CMD_FLAG_REQUEST)) { 390 if (!(hdr->msg_flags & CMD_FLAG_REQUEST)) {
343 struct msg * req; 391 struct msg * req;
344 /* Search matching request (same hbhid) */ 392 /* Search matching request (same hbhid) */
345 CHECK_FCT_DO( fd_p_sr_fetch(&peer->p_sr, hdr->msg_hbhid, &req), goto psm_end ); 393 CHECK_FCT_DO( fd_p_sr_fetch(&peer->p_sr, hdr->msg_hbhid, &req), goto psm_end );
346 if (req == NULL) { 394 if (req == NULL) {
347 fd_log_debug("Received a Diameter answer message with no corresponding sent request, discarding...\n"); 395 fd_log_debug("Received a Diameter answer message with no corresponding sent request, discarding.\n");
348 fd_msg_dump_walk(NONE, msg); 396 fd_msg_dump_walk(NONE, msg);
349 fd_msg_free(msg); 397 fd_msg_free(msg);
350 goto psm_loop; 398 goto psm_loop;
351 } 399 }
352 400
354 CHECK_FCT_DO( fd_msg_answ_associate( msg, req ), goto psm_end ); 402 CHECK_FCT_DO( fd_msg_answ_associate( msg, req ), goto psm_end );
355 } 403 }
356 404
357 /* Now handle non-link-local messages */ 405 /* Now handle non-link-local messages */
358 if (fd_msg_is_routable(msg)) { 406 if (fd_msg_is_routable(msg)) {
359 /* If we are not in OPEN state, discard the message */ 407 switch (peer->p_hdr.info.runtime.pir_state) {
360 if (peer->p_hdr.info.pi_state != STATE_OPEN) { 408 /* To maximize compatibility -- should not be a security issue here */
361 fd_log_debug("Received a routable message while not in OPEN state from peer '%s', discarded.\n", peer->p_hdr.info.pi_diamid); 409 case STATE_REOPEN:
362 fd_msg_dump_walk(NONE, msg); 410 case STATE_SUSPECT:
363 fd_msg_free(msg); 411 case STATE_CLOSING:
364 } else { 412 TRACE_DEBUG(FULL, "Accepted a message while not in OPEN state");
365 /* We received a valid message, update the expiry timer */ 413 /* The standard situation : */
366 CHECK_FCT_DO( fd_p_expi_update(peer), goto psm_end ); 414 case STATE_OPEN:
367 415 /* We received a valid message, update the expiry timer */
368 /* Set the message source and add the Route-Record */ 416 CHECK_FCT_DO( fd_p_expi_update(peer), goto psm_end );
369 CHECK_FCT_DO( fd_msg_source_set( msg, peer->p_hdr.info.pi_diamid, 1, fd_g_config->cnf_dict ), goto psm_end); 417
370 418 /* Set the message source and add the Route-Record */
371 /* Requeue to the global incoming queue */ 419 CHECK_FCT_DO( fd_msg_source_set( msg, peer->p_hdr.info.pi_diamid, 1, fd_g_config->cnf_dict ), goto psm_end);
372 CHECK_FCT_DO(fd_fifo_post(fd_g_incoming, &msg), goto psm_end ); 420
373 421 /* Requeue to the global incoming queue */
374 /* Update the peer timer */ 422 CHECK_FCT_DO(fd_fifo_post(fd_g_incoming, &msg), goto psm_end );
375 if (!peer->p_flags.pf_dw_pending) { 423
376 fd_psm_next_timeout(peer, 1, peer->p_hdr.info.pi_twtimer ?: fd_g_config->cnf_timer_tw); 424 /* Update the peer timer (only in OPEN state) */
377 } 425 if ((peer->p_hdr.info.runtime.pir_state == STATE_OPEN) && (!peer->p_flags.pf_dw_pending)) {
426 fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw);
427 }
428 break;
429
430 /* In other states, we discard the message, it is either old or invalid to send it for the remote peer */
431 case STATE_WAITCNXACK:
432 case STATE_WAITCNXACK_ELEC:
433 case STATE_WAITCEA:
434 case STATE_CLOSED:
435 default:
436 /* In such case, just discard the message */
437 fd_log_debug("Received a routable message while not in OPEN state from peer '%s', discarded.\n", peer->p_hdr.info.pi_diamid);
438 fd_msg_dump_walk(NONE, msg);
439 fd_msg_free(msg);
378 } 440 }
379 goto psm_loop; 441 goto psm_loop;
380 } 442 }
381 443
382 /* Link-local message: They must be understood by our dictionary */ 444 /* Link-local message: They must be understood by our dictionary, otherwise we return an error */
383 { 445 {
384 int ret; 446 int ret;
385 CHECK_FCT_DO( ret = fd_msg_parse_or_error( &msg ), 447 CHECK_FCT_DO( ret = fd_msg_parse_or_error( &msg ),
386 { 448 {
387 if ((ret == EBADMSG) && (msg != NULL)) { 449 if ((ret == EBADMSG) && (msg != NULL)) {
393 } 455 }
394 goto psm_loop; 456 goto psm_loop;
395 } ); 457 } );
396 } 458 }
397 459
398 ASSERT( hdr->msg_appl == 0 ); /* buggy fd_msg_is_routable() ? */
399
400 /* Handle the LL message and update the expiry timer appropriately */ 460 /* Handle the LL message and update the expiry timer appropriately */
401 switch (hdr->msg_code) { 461 switch (hdr->msg_code) {
402 case CC_DEVICE_WATCHDOG: 462 case CC_CAPABILITIES_EXCHANGE:
403 CHECK_FCT_DO( fd_p_dw_handle(&msg, peer), goto psm_end ); 463 CHECK_FCT_DO( fd_p_ce_handle(&msg, peer), goto psm_end );
404 break; 464 break;
405 465
406 case CC_DISCONNECT_PEER: 466 case CC_DISCONNECT_PEER:
407 CHECK_FCT_DO( fd_p_dp_handle(&msg, peer), goto psm_end ); 467 CHECK_FCT_DO( fd_p_dp_handle(&msg, peer), goto psm_end );
408 break; 468 break;
409 469
410 case CC_CAPABILITIES_EXCHANGE: 470 case CC_DEVICE_WATCHDOG:
411 CHECK_FCT_DO( fd_p_ce_handle(&msg, peer), goto psm_end ); 471 CHECK_FCT_DO( fd_p_dw_handle(&msg, peer), goto psm_end );
412 break; 472 break;
413 473
414 default: 474 default:
415 /* Unknown / unexpected / invalid message */ 475 /* Unknown / unexpected / invalid message */
416 TODO("Log, return error message if request"); 476 fd_log_debug("Received an unknown local message from peer '%s', discarded.\n", peer->p_hdr.info.pi_diamid);
477 fd_msg_dump_walk(NONE, msg);
478 if (hdr->msg_flags & CMD_FLAG_REQUEST) {
479 do {
480 /* Reply with an error code */
481 CHECK_FCT_DO( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &msg, MSGFL_ANSW_ERROR ), break );
482
483 /* Set the error code */
484 CHECK_FCT_DO( fd_msg_rescode_set(msg, "DIAMETER_INVALID_HDR_BITS", NULL, NULL, 1 ), break );
485
486 /* Send the answer */
487 CHECK_FCT_DO( fd_out_send(&msg, peer->p_cnxctx, peer), break );
488 } while (0);
489 } else {
490 /* We did ASK for it ??? */
491 fd_log_debug("Invalid PXY flag in header ?\n");
492 }
493
494 /* Cleanup the message if not done */
495 if (msg) {
496 CHECK_FCT_DO( fd_msg_free(msg), /* continue */);
497 msg = NULL;
498 }
417 }; 499 };
418 500
419 /* At this point the message must have been fully handled already */ 501 /* At this point the message must have been fully handled already */
420 if (msg) { 502 if (msg) {
421 fd_log_debug("Internal error: unhandled message (discarded)!\n"); 503 fd_log_debug("Internal error: unhandled message (discarded)!\n");
426 goto psm_loop; 508 goto psm_loop;
427 } 509 }
428 510
429 /* The connection object is broken */ 511 /* The connection object is broken */
430 if (event == FDEVP_CNX_ERROR) { 512 if (event == FDEVP_CNX_ERROR) {
431 /* Cleanup the peer */ 513 switch (peer->p_hdr.info.runtime.pir_state) {
432 fd_psm_cleanup(peer); 514 case STATE_WAITCNXACK_ELEC:
433 515 TODO("Reply CEA on the receiver side and go to OPEN state");
434 /* Mark the connection problem */ 516 goto psm_loop;
435 peer->p_flags.pf_cnx_pb = 1; 517
436 518 case STATE_OPEN:
437 /* Move to CLOSED */ 519 case STATE_REOPEN:
438 CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), goto psm_end ); 520 case STATE_WAITCNXACK:
439 521 case STATE_WAITCEA:
440 /* Reset the timer */ 522 case STATE_SUSPECT:
441 fd_psm_next_timeout(peer, 1, peer->p_hdr.info.pi_tctimer ?: fd_g_config->cnf_timer_tc); 523 default:
442 524 /* Mark the connection problem */
443 /* Loop */ 525 peer->p_flags.pf_cnx_pb = 1;
444 goto psm_loop; 526
527 case STATE_CLOSING:
528 /* Cleanup the peer */
529 fd_psm_cleanup(peer);
530
531 /* Reset the timer */
532 fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc);
533
534 case STATE_CLOSED:
535 /* Go to the next event */
536 goto psm_loop;
537 }
445 } 538 }
446 539
447 /* The connection notified a change in endpoints */ 540 /* The connection notified a change in endpoints */
448 if (event == FDEVP_CNX_EP_CHANGE) { 541 if (event == FDEVP_CNX_EP_CHANGE) {
542 /* We actually don't care if we are in OPEN state here... */
543
449 /* Cleanup the remote LL and primary addresses */ 544 /* Cleanup the remote LL and primary addresses */
450 CHECK_FCT_DO( fd_ep_filter( &peer->p_hdr.info.pi_endpoints, EP_FL_CONF | EP_FL_DISC | EP_FL_ADV ), /* ignore the error */); 545 CHECK_FCT_DO( fd_ep_filter( &peer->p_hdr.info.pi_endpoints, EP_FL_CONF | EP_FL_DISC | EP_FL_ADV ), /* ignore the error */);
451 CHECK_FCT_DO( fd_ep_clearflags( &peer->p_hdr.info.pi_endpoints, EP_FL_PRIMARY ), /* ignore the error */); 546 CHECK_FCT_DO( fd_ep_clearflags( &peer->p_hdr.info.pi_endpoints, EP_FL_PRIMARY ), /* ignore the error */);
452 547
453 /* Get the new ones */ 548 /* Get the new ones */
454 CHECK_FCT_DO( fd_cnx_getendpoints(peer->p_cnxctx, NULL, &peer->p_hdr.info.pi_endpoints), /* ignore the error */); 549 CHECK_FCT_DO( fd_cnx_getendpoints(peer->p_cnxctx, NULL, &peer->p_hdr.info.pi_endpoints), /* ignore the error */);
455 550
551 /* We do not support local endpoints change currently, but it could be added here if needed */
552
456 if (TRACE_BOOL(ANNOYING)) { 553 if (TRACE_BOOL(ANNOYING)) {
457 fd_log_debug("New remote endpoint(s):\n"); 554 TRACE_DEBUG(ANNOYING, "New remote endpoint(s):" );
458 fd_ep_dump(6, &peer->p_hdr.info.pi_endpoints); 555 fd_ep_dump(6, &peer->p_hdr.info.pi_endpoints);
459 } 556 }
460 557
461 /* Done */ 558 /* Done */
462 goto psm_loop; 559 goto psm_loop;
485 goto psm_loop; 582 goto psm_loop;
486 } 583 }
487 584
488 /* The timeout for the current state has been reached */ 585 /* The timeout for the current state has been reached */
489 if (event == FDEVP_PSM_TIMEOUT) { 586 if (event == FDEVP_PSM_TIMEOUT) {
490 switch (peer->p_hdr.info.pi_state) { 587 switch (peer->p_hdr.info.runtime.pir_state) {
491 case STATE_OPEN: 588 case STATE_OPEN:
492 case STATE_REOPEN: 589 case STATE_REOPEN:
493 CHECK_FCT_DO( fd_p_dw_timeout(peer), goto psm_end ); 590 CHECK_FCT_DO( fd_p_dw_timeout(peer), goto psm_end );
494 break; 591 break;
495 592
496 case STATE_CLOSED: 593 case STATE_CLOSED:
497 TODO("Initiate a new connection"); 594 CHECK_FCT_DO( fd_psm_change_state(peer, STATE_WAITCNXACK), goto psm_end );
595 fd_psm_next_timeout(peer, 0, CNX_TIMEOUT);
596 CHECK_FCT_DO( fd_p_cnx_init(peer), goto psm_end );
498 break; 597 break;
499 598
500 case STATE_CLOSING: 599 case STATE_CLOSING:
501 case STATE_SUSPECT: 600 case STATE_SUSPECT:
502 case STATE_WAITCNXACK: 601 case STATE_WAITCNXACK:
503 case STATE_WAITCEA: 602 case STATE_WAITCEA:
504 /* Destroy the connection, restart the timer to a new connection attempt */ 603 /* Destroy the connection, restart the timer to a new connection attempt */
505 fd_psm_cleanup(peer); 604 fd_psm_cleanup(peer);
506 fd_psm_next_timeout(peer, 1, peer->p_hdr.info.pi_tctimer ?: fd_g_config->cnf_timer_tc); 605 fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc);
507 CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), goto psm_end );
508 break; 606 break;
509 607
510 case STATE_WAITCNXACK_ELEC: 608 case STATE_WAITCNXACK_ELEC:
511 TODO("Abort initiating side, handle the receiver side"); 609 TODO("Abort initiating side, handle the receiver side");
512 break; 610 break;
513 } 611 }
514 } 612 }
515 613
516 /* Default action : the handling has not yet been implemented. [for debug only] */ 614 /* Default action : the handling has not yet been implemented. [for debug only] */
517 TODO("Missing handler in PSM : '%s'\t<-- '%s'", STATE_STR(peer->p_hdr.info.pi_state), fd_pev_str(event)); 615 TODO("Missing handler in PSM : '%s'\t<-- '%s'", STATE_STR(peer->p_hdr.info.runtime.pir_state), fd_pev_str(event));
518 if (event == FDEVP_PSM_TIMEOUT) { 616 if (event == FDEVP_PSM_TIMEOUT) {
519 /* We have not handled timeout in this state, let's postpone next alert */ 617 /* We have not handled timeout in this state, let's postpone next alert */
520 fd_psm_next_timeout(peer, 0, 60); 618 fd_psm_next_timeout(peer, 0, 60);
521 } 619 }
522 620
523 goto psm_loop; 621 goto psm_loop;
524 622
525 psm_end: 623 psm_end:
526 fd_psm_cleanup(peer); 624 fd_psm_cleanup(peer);
625 CHECK_FCT_DO( fd_fifo_del(&peer->p_events), /* continue */ );
527 pthread_cleanup_pop(1); /* set STATE_ZOMBIE */ 626 pthread_cleanup_pop(1); /* set STATE_ZOMBIE */
528 peer->p_psm = (pthread_t)NULL; 627 peer->p_psm = (pthread_t)NULL;
529 pthread_detach(pthread_self()); 628 pthread_detach(pthread_self());
530 return NULL; 629 return NULL;
531 } 630 }
538 int fd_psm_begin(struct fd_peer * peer ) 637 int fd_psm_begin(struct fd_peer * peer )
539 { 638 {
540 TRACE_ENTRY("%p", peer); 639 TRACE_ENTRY("%p", peer);
541 640
542 /* Check the peer and state are OK */ 641 /* Check the peer and state are OK */
543 CHECK_PARAMS( CHECK_PEER(peer) && (peer->p_hdr.info.pi_state == STATE_NEW) ); 642 CHECK_PARAMS( CHECK_PEER(peer) && (peer->p_hdr.info.runtime.pir_state == STATE_NEW) );
643
644 /* Create the FIFO for events */
645 CHECK_FCT( fd_fifo_new(&peer->p_events) );
544 646
545 /* Create the PSM controler thread */ 647 /* Create the PSM controler thread */
546 CHECK_POSIX( pthread_create( &peer->p_psm, NULL, p_psm_th, peer ) ); 648 CHECK_POSIX( pthread_create( &peer->p_psm, NULL, p_psm_th, peer ) );
547 649
548 /* We're done */ 650 /* We're done */
553 int fd_psm_terminate(struct fd_peer * peer ) 655 int fd_psm_terminate(struct fd_peer * peer )
554 { 656 {
555 TRACE_ENTRY("%p", peer); 657 TRACE_ENTRY("%p", peer);
556 CHECK_PARAMS( CHECK_PEER(peer) ); 658 CHECK_PARAMS( CHECK_PEER(peer) );
557 659
558 if (peer->p_hdr.info.pi_state != STATE_ZOMBIE) { 660 if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) {
559 CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) ); 661 CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) );
560 } else { 662 } else {
561 TRACE_DEBUG(FULL, "Peer '%s' was already terminated", peer->p_hdr.info.pi_diamid); 663 TRACE_DEBUG(FULL, "Peer '%s' was already terminated", peer->p_hdr.info.pi_diamid);
562 } 664 }
563 return 0; 665 return 0;
569 TRACE_ENTRY("%p", peer); 671 TRACE_ENTRY("%p", peer);
570 672
571 /* Cancel PSM thread */ 673 /* Cancel PSM thread */
572 CHECK_FCT_DO( fd_thr_term(&peer->p_psm), /* continue */ ); 674 CHECK_FCT_DO( fd_thr_term(&peer->p_psm), /* continue */ );
573 675
574 /* Cancel the OUT thread */ 676 /* Cleanup the data */
575 CHECK_FCT_DO( fd_out_stop(peer), /* continue */ ); 677 fd_psm_cleanup(peer);
576 678
577 /* Cleanup the connection */ 679 /* Destroy the event list */
578 if (peer->p_cnxctx) { 680 CHECK_FCT_DO( fd_fifo_del(&peer->p_events), /* continue */ );
579 fd_cnx_destroy(peer->p_cnxctx); 681
580 } 682 /* Remaining cleanups are performed in fd_peer_free */
581
582 /* Failover the messages */
583 fd_peer_failover_msg(peer);
584
585 /* Empty the events list, this might leak some memory, but we only do it on exit, so... */
586 fd_event_destroy(&peer->p_events, free);
587
588 /* More cleanups are performed in fd_peer_free */
589 return; 683 return;
590 } 684 }
591 685
"Welcome to our mercurial repository"