Mercurial > hg > freeDiameter
comparison freeDiameter/p_psm.c @ 36:1498b3c7304c
Backup
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Mon, 02 Nov 2009 17:31:36 +0900 |
parents | 6486e97f56ae |
children | cc3c59fe98fe |
comparison
equal
deleted
inserted
replaced
35:6486e97f56ae | 36:1498b3c7304c |
---|---|
143 | 143 |
144 /************************************************************************/ | 144 /************************************************************************/ |
145 /* Helpers for state changes */ | 145 /* Helpers for state changes */ |
146 /************************************************************************/ | 146 /************************************************************************/ |
147 /* Change state */ | 147 /* Change state */ |
148 static int change_state(struct fd_peer * peer, int new_state) | 148 int fd_psm_change_state(struct fd_peer * peer, int new_state) |
149 { | 149 { |
150 int old; | 150 int old; |
151 | 151 |
152 TRACE_ENTRY("%p %d(%s)", peer, new_state, STATE_STR(new_state)); | 152 TRACE_ENTRY("%p %d(%s)", peer, new_state, STATE_STR(new_state)); |
153 CHECK_PARAMS( CHECK_PEER(peer) ); | 153 CHECK_PARAMS( CHECK_PEER(peer) ); |
168 | 168 |
169 if (new_state == STATE_OPEN) { | 169 if (new_state == STATE_OPEN) { |
170 CHECK_FCT( enter_open_state(peer) ); | 170 CHECK_FCT( enter_open_state(peer) ); |
171 } | 171 } |
172 | 172 |
173 if ((new_state == STATE_CLOSED) && (peer->p_hdr.info.pi_flags.persist == PI_PRST_NONE)) { | |
174 CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) ); | |
175 } | |
176 | |
173 return 0; | 177 return 0; |
174 } | 178 } |
175 | 179 |
176 /* Set timeout timer of next event */ | 180 /* Set timeout timer of next event */ |
177 static void psm_next_timeout(struct fd_peer * peer, int add_random, int delay) | 181 void fd_psm_next_timeout(struct fd_peer * peer, int add_random, int delay) |
178 { | 182 { |
179 /* Initialize the timer */ | 183 /* Initialize the timer */ |
180 CHECK_POSIX_DO( clock_gettime( CLOCK_REALTIME, &peer->p_psm_timer ), ASSERT(0) ); | 184 CHECK_POSIX_DO( clock_gettime( CLOCK_REALTIME, &peer->p_psm_timer ), ASSERT(0) ); |
181 | 185 |
182 if (add_random) { | 186 if (add_random) { |
200 /* temporary for debug */ | 204 /* temporary for debug */ |
201 peer->p_psm_timer.tv_sec += 10; | 205 peer->p_psm_timer.tv_sec += 10; |
202 #endif | 206 #endif |
203 } | 207 } |
204 | 208 |
209 /* Cleanup the peer */ | |
210 void fd_psm_cleanup(struct fd_peer * peer) | |
211 { | |
212 /* Move to CLOSED state */ | |
213 CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), /* continue */ ); | |
214 | |
215 /* Destroy the connection */ | |
216 if (peer->p_cnxctx) { | |
217 fd_cnx_destroy(peer->p_cnxctx); | |
218 peer->p_cnxctx = NULL; | |
219 } | |
220 | |
221 /* What else ? */ | |
222 TODO("..."); | |
223 | |
224 } | |
225 | |
205 | 226 |
206 /************************************************************************/ | 227 /************************************************************************/ |
207 /* The PSM thread */ | 228 /* The PSM thread */ |
208 /************************************************************************/ | 229 /************************************************************************/ |
209 /* Cancelation cleanup : set ZOMBIE state in the peer */ | 230 /* Cancelation cleanup : set ZOMBIE state in the peer */ |
210 void cleanup_state(void * arg) | 231 void cleanup_setstate(void * arg) |
211 { | 232 { |
212 struct fd_peer * peer = (struct fd_peer *)arg; | 233 struct fd_peer * peer = (struct fd_peer *)arg; |
213 CHECK_PARAMS_DO( CHECK_PEER(peer), return ); | 234 CHECK_PARAMS_DO( CHECK_PEER(peer), return ); |
214 peer->p_hdr.info.pi_state = STATE_ZOMBIE; | 235 peer->p_hdr.info.pi_state = STATE_ZOMBIE; |
215 return; | 236 return; |
224 size_t ev_sz; | 245 size_t ev_sz; |
225 void * ev_data; | 246 void * ev_data; |
226 | 247 |
227 CHECK_PARAMS_DO( CHECK_PEER(peer), ASSERT(0) ); | 248 CHECK_PARAMS_DO( CHECK_PEER(peer), ASSERT(0) ); |
228 | 249 |
229 pthread_cleanup_push( cleanup_state, arg ); | 250 pthread_cleanup_push( cleanup_setstate, arg ); |
230 | 251 |
231 /* Set the thread name */ | 252 /* Set the thread name */ |
232 { | 253 { |
233 char buf[48]; | 254 char buf[48]; |
234 sprintf(buf, "PSM/%.*s", sizeof(buf) - 5, peer->p_hdr.info.pi_diamid); | 255 sprintf(buf, "PSM/%.*s", sizeof(buf) - 5, peer->p_hdr.info.pi_diamid); |
241 /* Wait that the PSM are authorized to start in the daemon */ | 262 /* Wait that the PSM are authorized to start in the daemon */ |
242 CHECK_FCT_DO( fd_psm_waitstart(), goto psm_end ); | 263 CHECK_FCT_DO( fd_psm_waitstart(), goto psm_end ); |
243 | 264 |
244 /* Initialize the timer */ | 265 /* Initialize the timer */ |
245 if (peer->p_flags.pf_responder) { | 266 if (peer->p_flags.pf_responder) { |
246 psm_next_timeout(peer, 0, INCNX_TIMEOUT); | 267 fd_psm_next_timeout(peer, 0, INCNX_TIMEOUT); |
247 } else { | 268 } else { |
248 psm_next_timeout(peer, created_started, 0); | 269 fd_psm_next_timeout(peer, created_started, 0); |
249 } | 270 } |
250 | 271 |
251 psm_loop: | 272 psm_loop: |
252 /* Get next event */ | 273 /* Get next event */ |
253 CHECK_FCT_DO( fd_event_timedget(peer->p_events, &peer->p_psm_timer, FDEVP_PSM_TIMEOUT, &event, &ev_sz, &ev_data), goto psm_end ); | 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 ); |
276 } | 297 } |
277 | 298 |
278 /* Requests to terminate the peer object */ | 299 /* Requests to terminate the peer object */ |
279 if (event == FDEVP_TERMINATE) { | 300 if (event == FDEVP_TERMINATE) { |
280 switch (peer->p_hdr.info.pi_state) { | 301 switch (peer->p_hdr.info.pi_state) { |
302 case STATE_OPEN: | |
303 case STATE_REOPEN: | |
304 /* 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 ); | |
306 goto psm_loop; | |
307 | |
308 /* | |
281 case STATE_CLOSING: | 309 case STATE_CLOSING: |
282 case STATE_WAITCNXACK: | 310 case STATE_WAITCNXACK: |
283 case STATE_WAITCNXACK_ELEC: | 311 case STATE_WAITCNXACK_ELEC: |
284 case STATE_WAITCEA: | 312 case STATE_WAITCEA: |
285 case STATE_SUSPECT: | 313 case STATE_SUSPECT: |
286 /* In these cases, we just cleanup the peer object and terminate now */ | |
287 TODO("Cleanup the PSM: terminate connection object, ..."); | |
288 case STATE_CLOSED: | 314 case STATE_CLOSED: |
289 /* Then we just terminate the PSM */ | 315 */ |
316 default: | |
317 /* In these cases, we just cleanup the peer object (if needed) and terminate */ | |
290 goto psm_end; | 318 goto psm_end; |
291 | |
292 case STATE_OPEN: | |
293 case STATE_REOPEN: | |
294 /* We cannot just close the conenction, we have to send a DPR first */ | |
295 TODO("Send DPR, mark the peer as CLOSING"); | |
296 goto psm_loop; | |
297 } | 319 } |
298 } | 320 } |
299 | 321 |
300 /* A message was received */ | 322 /* A message was received */ |
301 if (event == FDEVP_CNX_MSG_RECV) { | 323 if (event == FDEVP_CNX_MSG_RECV) { |
308 fd_log_debug("Received invalid data from peer '%s', closing the connection\n", peer->p_hdr.info.pi_diamid); | 330 fd_log_debug("Received invalid data from peer '%s', closing the connection\n", peer->p_hdr.info.pi_diamid); |
309 CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL), goto psm_end ); | 331 CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL), goto psm_end ); |
310 goto psm_loop; | 332 goto psm_loop; |
311 } ); | 333 } ); |
312 | 334 |
313 TRACE_DEBUG(FULL, "Received this message from '%s':", peer->p_hdr.info.pi_diamid); | 335 TRACE_DEBUG(FULL, "Received a message (%zdb) from '%s'", ev_sz, peer->p_hdr.info.pi_diamid); |
314 fd_msg_dump_walk(FULL, msg); | 336 fd_msg_dump_walk(FULL + 1, msg); |
315 | 337 |
316 /* Extract the header */ | 338 /* Extract the header */ |
317 CHECK_FCT_DO( fd_msg_hdr(msg, &hdr), goto psm_end ); | 339 CHECK_FCT_DO( fd_msg_hdr(msg, &hdr), goto psm_end ); |
318 | 340 |
319 /* If it is an answer, associate with the request */ | 341 /* If it is an answer, associate with the request */ |
330 | 352 |
331 /* Associate */ | 353 /* Associate */ |
332 CHECK_FCT_DO( fd_msg_answ_associate( msg, req ), goto psm_end ); | 354 CHECK_FCT_DO( fd_msg_answ_associate( msg, req ), goto psm_end ); |
333 } | 355 } |
334 | 356 |
335 /* We received a valid message, update the expiry timer */ | |
336 CHECK_FCT_DO( fd_p_expi_update(peer), goto psm_end ); | |
337 | |
338 /* Now handle non-link-local messages */ | 357 /* Now handle non-link-local messages */ |
339 if (fd_msg_is_routable(msg)) { | 358 if (fd_msg_is_routable(msg)) { |
340 /* If we are not in OPEN state, discard the message */ | 359 /* If we are not in OPEN state, discard the message */ |
341 if (peer->p_hdr.info.pi_state != STATE_OPEN) { | 360 if (peer->p_hdr.info.pi_state != STATE_OPEN) { |
342 fd_log_debug("Received a routable message while not in OPEN state from peer '%s', discarded.\n", peer->p_hdr.info.pi_diamid); | 361 fd_log_debug("Received a routable message while not in OPEN state from peer '%s', discarded.\n", peer->p_hdr.info.pi_diamid); |
343 fd_msg_dump_walk(NONE, msg); | 362 fd_msg_dump_walk(NONE, msg); |
344 fd_msg_free(msg); | 363 fd_msg_free(msg); |
345 } else { | 364 } else { |
365 /* We received a valid message, update the expiry timer */ | |
366 CHECK_FCT_DO( fd_p_expi_update(peer), goto psm_end ); | |
367 | |
346 /* Set the message source and add the Route-Record */ | 368 /* Set the message source and add the Route-Record */ |
347 CHECK_FCT_DO( fd_msg_source_set( msg, peer->p_hdr.info.pi_diamid, 1, fd_g_config->cnf_dict ), 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); |
348 | 370 |
349 /* Requeue to the global incoming queue */ | 371 /* Requeue to the global incoming queue */ |
350 CHECK_FCT_DO(fd_fifo_post(fd_g_incoming, &msg), goto psm_end ); | 372 CHECK_FCT_DO(fd_fifo_post(fd_g_incoming, &msg), goto psm_end ); |
351 | 373 |
352 /* Update the peer timer */ | 374 /* Update the peer timer */ |
353 if (!peer->p_flags.pf_dw_pending) { | 375 if (!peer->p_flags.pf_dw_pending) { |
354 psm_next_timeout(peer, 1, peer->p_hdr.info.pi_twtimer ?: fd_g_config->cnf_timer_tw); | 376 fd_psm_next_timeout(peer, 1, peer->p_hdr.info.pi_twtimer ?: fd_g_config->cnf_timer_tw); |
355 } | 377 } |
356 } | 378 } |
357 goto psm_loop; | 379 goto psm_loop; |
358 } | 380 } |
359 | 381 |
371 } | 393 } |
372 goto psm_loop; | 394 goto psm_loop; |
373 } ); | 395 } ); |
374 } | 396 } |
375 | 397 |
398 ASSERT( hdr->msg_appl == 0 ); /* buggy fd_msg_is_routable() ? */ | |
399 | |
376 /* Handle the LL message and update the expiry timer appropriately */ | 400 /* Handle the LL message and update the expiry timer appropriately */ |
377 TODO("..."); | 401 switch (hdr->msg_code) { |
402 case CC_DEVICE_WATCHDOG: | |
403 CHECK_FCT_DO( fd_p_dw_handle(&msg, peer), goto psm_end ); | |
404 break; | |
405 | |
406 case CC_DISCONNECT_PEER: | |
407 CHECK_FCT_DO( fd_p_dp_handle(&msg, peer), goto psm_end ); | |
408 break; | |
409 | |
410 case CC_CAPABILITIES_EXCHANGE: | |
411 CHECK_FCT_DO( fd_p_ce_handle(&msg, peer), goto psm_end ); | |
412 break; | |
413 | |
414 default: | |
415 /* Unknown / unexpected / invalid message */ | |
416 TODO("Log, return error message if request"); | |
417 }; | |
418 | |
419 /* At this point the message must have been fully handled already */ | |
420 if (msg) { | |
421 fd_log_debug("Internal error: unhandled message (discarded)!\n"); | |
422 fd_msg_dump_walk(NONE, msg); | |
423 fd_msg_free(msg); | |
424 } | |
425 | |
426 goto psm_loop; | |
378 } | 427 } |
379 | 428 |
380 /* The connection object is broken */ | 429 /* The connection object is broken */ |
381 if (event == FDEVP_CNX_ERROR) { | 430 if (event == FDEVP_CNX_ERROR) { |
382 TODO("Destroy the connection object"); | 431 /* Cleanup the peer */ |
383 TODO("Mark the error in the peer (pf_cnx_pb)"); | 432 fd_psm_cleanup(peer); |
384 TODO("Move to closed state, Requeue all messages to a different connection (failover)"); | 433 |
385 TODO("If pi_flags.exp, terminate the peer"); | 434 /* Mark the connection problem */ |
435 peer->p_flags.pf_cnx_pb = 1; | |
436 | |
437 /* Move to CLOSED */ | |
438 CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), goto psm_end ); | |
439 | |
440 /* Reset the timer */ | |
441 fd_psm_next_timeout(peer, 1, peer->p_hdr.info.pi_tctimer ?: fd_g_config->cnf_timer_tc); | |
442 | |
443 /* Loop */ | |
444 goto psm_loop; | |
386 } | 445 } |
387 | 446 |
388 /* The connection notified a change in endpoints */ | 447 /* The connection notified a change in endpoints */ |
389 if (event == FDEVP_CNX_EP_CHANGE) { | 448 if (event == FDEVP_CNX_EP_CHANGE) { |
390 /* Cleanup the remote LL and primary addresses */ | 449 /* Cleanup the remote LL and primary addresses */ |
406 /* A new connection was established and CER containing this peer id was received */ | 465 /* A new connection was established and CER containing this peer id was received */ |
407 if (event == FDEVP_CNX_INCOMING) { | 466 if (event == FDEVP_CNX_INCOMING) { |
408 struct cnx_incoming * params = ev_data; | 467 struct cnx_incoming * params = ev_data; |
409 ASSERT(params); | 468 ASSERT(params); |
410 | 469 |
411 switch (peer->p_hdr.info.pi_state) { | 470 /* Handle the message */ |
412 case STATE_CLOSED: | 471 CHECK_FCT_DO( fd_p_ce_handle_newCER(¶ms->cer, peer, ¶ms->cnx, params->validate), goto psm_end ); |
413 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"); | 472 |
414 /* In case of error : DIAMETER_UNKNOWN_PEER */ | 473 /* Cleanup if needed */ |
415 | 474 if (params->cnx) { |
416 CHECK_FCT_DO( fd_p_ce_merge(peer, params->cer), | 475 fd_cnx_destroy(params->cnx); |
417 { | 476 params->cnx = NULL; |
418 | 477 } |
419 } ); | 478 if (params->cer) { |
420 | 479 CHECK_FCT_DO( fd_msg_free(params->cer), ); |
421 break; | 480 params->cer = NULL; |
422 | 481 } |
423 case STATE_WAITCNXACK: | 482 |
424 case STATE_WAITCEA: | 483 /* Loop */ |
425 TODO("Election"); | |
426 break; | |
427 | |
428 default: | |
429 TODO("Reply with error CEA"); | |
430 TODO("Close the connection"); | |
431 /* reject_incoming_connection */ | |
432 | |
433 } | |
434 | |
435 free(ev_data); | 484 free(ev_data); |
436 goto psm_loop; | 485 goto psm_loop; |
437 } | 486 } |
438 | 487 |
439 /* The timeout for the current state has been reached */ | 488 /* The timeout for the current state has been reached */ |
440 if (event == FDEVP_PSM_TIMEOUT) { | 489 if (event == FDEVP_PSM_TIMEOUT) { |
441 switch (peer->p_hdr.info.pi_state) { | 490 switch (peer->p_hdr.info.pi_state) { |
442 | 491 case STATE_OPEN: |
443 | 492 case STATE_REOPEN: |
493 CHECK_FCT_DO( fd_p_dw_timeout(peer), goto psm_end ); | |
494 break; | |
495 | |
496 case STATE_CLOSED: | |
497 TODO("Initiate a new connection"); | |
498 break; | |
499 | |
500 case STATE_CLOSING: | |
501 case STATE_SUSPECT: | |
502 case STATE_WAITCNXACK: | |
503 case STATE_WAITCEA: | |
504 /* Destroy the connection, restart the timer to a new connection attempt */ | |
505 fd_psm_cleanup(peer); | |
506 fd_psm_next_timeout(peer, 1, peer->p_hdr.info.pi_tctimer ?: fd_g_config->cnf_timer_tc); | |
507 CHECK_FCT_DO( fd_psm_change_state(peer, STATE_CLOSED), goto psm_end ); | |
508 break; | |
509 | |
510 case STATE_WAITCNXACK_ELEC: | |
511 TODO("Abort initiating side, handle the receiver side"); | |
512 break; | |
444 } | 513 } |
445 } | 514 } |
446 | 515 |
447 /* Default action : the handling has not yet been implemented. [for debug only] */ | 516 /* Default action : the handling has not yet been implemented. [for debug only] */ |
448 TODO("Missing handler in PSM : '%s'\t<-- '%s'", STATE_STR(peer->p_hdr.info.pi_state), fd_pev_str(event)); | 517 TODO("Missing handler in PSM : '%s'\t<-- '%s'", STATE_STR(peer->p_hdr.info.pi_state), fd_pev_str(event)); |
449 if (event == FDEVP_PSM_TIMEOUT) { | 518 if (event == FDEVP_PSM_TIMEOUT) { |
450 /* We have not handled timeout in this state, let's postpone next alert */ | 519 /* We have not handled timeout in this state, let's postpone next alert */ |
451 psm_next_timeout(peer, 0, 60); | 520 fd_psm_next_timeout(peer, 0, 60); |
452 } | 521 } |
453 | 522 |
454 goto psm_loop; | 523 goto psm_loop; |
455 | 524 |
456 psm_end: | 525 psm_end: |
526 fd_psm_cleanup(peer); | |
457 pthread_cleanup_pop(1); /* set STATE_ZOMBIE */ | 527 pthread_cleanup_pop(1); /* set STATE_ZOMBIE */ |
458 peer->p_psm = (pthread_t)NULL; | 528 peer->p_psm = (pthread_t)NULL; |
459 pthread_detach(pthread_self()); | 529 pthread_detach(pthread_self()); |
460 return NULL; | 530 return NULL; |
461 } | 531 } |