Changeset 25:67ca08d5bc48 in freeDiameter
- Timestamp:
- Oct 26, 2009, 4:00:49 PM (15 years ago)
- Branch:
- default
- Phase:
- public
- Files:
-
- 2 added
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
extensions/dbg_monitor/monitor.c
r11 r25 49 49 static void got_sig(int signal) 50 50 { 51 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_DICT, NULL), /* continue */);52 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_CONFIG, NULL), /* continue */);53 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_EXT, NULL), /* continue */);51 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_DICT, 0, NULL), /* continue */); 52 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_CONFIG, 0, NULL), /* continue */); 53 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_EXT, 0, NULL), /* continue */); 54 54 } 55 55 /* Thread to display periodical debug information */ … … 77 77 #endif /* DEBUG */ 78 78 TRACE_DEBUG(NONE, "Monitor information"); 79 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_QUEUES, NULL), /* continue */); 80 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_PEERS, NULL), /* continue */); 79 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_QUEUES, 0, NULL), /* continue */); 80 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_SERV, 0, NULL), /* continue */); 81 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_PEERS, 0, NULL), /* continue */); 81 82 pthread_testcancel(); 82 83 } -
freeDiameter/CMakeLists.txt
r24 r25 10 10 SET(FD_COMMON_SRC 11 11 fD.h 12 cnxctx.h 12 13 config.c 13 14 cnxctx.c … … 26 27 27 28 IF(NOT DISABLE_SCTP) 28 SET(FD_COMMON_SRC ${FD_COMMON_SRC} sctp.c )29 SET(FD_COMMON_SRC ${FD_COMMON_SRC} sctp.c sctps.c) 29 30 ENDIF(NOT DISABLE_SCTP) 30 31 -
freeDiameter/cnxctx.c
r24 r25 35 35 36 36 #include "fD.h" 37 #include "cnxctx.h" 38 39 /* The maximum size of Diameter message we accept to receive (<= 2^24) to avoid too big mallocs in case of trashed headers */ 40 #ifndef DIAMETER_MSG_SIZE_MAX 41 #define DIAMETER_MSG_SIZE_MAX 65535 /* in bytes */ 42 #endif /* DIAMETER_MSG_SIZE_MAX */ 37 43 38 44 /* Connections contexts (cnxctx) in freeDiameter are wrappers around the sockets and TLS operations . … … 57 63 * 58 64 * 3) Usage 59 * - fd_cnx_receive, fd_cnx_send : exchange messages on this connection (send is synchronous, receive is not ).65 * - fd_cnx_receive, fd_cnx_send : exchange messages on this connection (send is synchronous, receive is not, but blocking). 60 66 * - fd_cnx_recv_setaltfifo : when a message is received, the event is sent to an external fifo list. fd_cnx_receive does not work when the alt_fifo is set. 61 67 * - fd_cnx_getid : retrieve a descriptive string for the connection (for debug) … … 68 74 */ 69 75 70 /* The connection context structure */ 71 struct cnxctx { 72 char cc_id[60]; /* The name of this connection */ 73 char cc_remid[60]; /* Id of remote peer */ 74 75 int cc_socket; /* The socket object of the connection -- <=0 if no socket is created */ 76 77 int cc_proto; /* IPPROTO_TCP or IPPROTO_SCTP */ 78 int cc_tls; /* Is TLS already started ? */ 79 80 struct fifo * cc_events; /* Events occuring on the connection */ 81 pthread_t cc_mgr; /* manager thread for the connection */ 82 struct fifo * cc_incoming; /* FIFO queue of messages received on the connection */ 83 struct fifo * cc_alt; /* alternate fifo to send FDEVP_CNX_MSG_RECV events to. */ 84 85 /* If cc_proto == SCTP */ 86 struct { 87 int str_out;/* Out streams */ 88 int str_in; /* In streams */ 89 int pairs; /* max number of pairs ( = min(in, out)) */ 90 int next; /* # of stream the next message will be sent to */ 91 } cc_sctp_para; 92 93 /* If cc_tls == true */ 94 struct { 95 int mode; /* GNUTLS_CLIENT / GNUTLS_SERVER */ 96 gnutls_session_t session; /* Session object (stream #0 in case of SCTP) */ 97 } cc_tls_para; 98 99 /* If both conditions */ 100 struct { 101 gnutls_session_t *res_sessions; /* Sessions of other pairs of streams, resumed from the first */ 102 /* Buffers, threads, ... */ 103 } cc_sctp_tls_para; 104 }; 105 76 77 /*******************************************/ 78 /* Creation of a connection object */ 79 /*******************************************/ 106 80 107 81 /* Initialize a context structure */ … … 116 90 117 91 if (full) { 118 CHECK_FCT_DO( fd_fifo_new ( &conn->cc_events ), return NULL );119 92 CHECK_FCT_DO( fd_fifo_new ( &conn->cc_incoming ), return NULL ); 120 93 } … … 352 325 } 353 326 354 /* Same for SCTP, accepts a list of remote addresses to connect to (see sctp_connectx ) */327 /* Same for SCTP, accepts a list of remote addresses to connect to (see sctp_connectx for how they are used) */ 355 328 struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list) 356 329 { … … 382 355 cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_in; 383 356 357 if (TRACE_BOOL(INFO)) { 358 fd_log_debug("Connection established to server '"); 359 sSA_DUMP_NODE_SERV( &primary, NI_NUMERICSERV); 360 fd_log_debug("' (SCTP:%d, %d/%d streams).\n", sock, cnx->cc_sctp_para.str_in, cnx->cc_sctp_para.str_out); 361 } 362 384 363 /* Generate the names for the object */ 385 364 { … … 403 382 } 404 383 405 if (TRACE_BOOL(INFO)) {406 fd_log_debug("Connection established to server '");407 sSA_DUMP_NODE_SERV( &primary, NI_NUMERICSERV);408 fd_log_debug("' (SCTP:%d).\n", sock);409 }410 411 384 return cnx; 412 385 … … 424 397 } 425 398 399 /* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */ 400 int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote) 401 { 402 TRACE_ENTRY("%p %p %p", conn, local, remote); 403 CHECK_PARAMS(conn); 404 405 if (local) { 406 /* Retrieve the local endpoint(s) of the connection */ 407 switch (conn->cc_proto) { 408 case IPPROTO_TCP: { 409 sSS ss; 410 socklen_t sl; 411 CHECK_FCT(fd_tcp_get_local_ep(conn->cc_socket, &ss, &sl)); 412 CHECK_FCT(fd_ep_add_merge( local, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY)); 413 } 414 break; 415 416 #ifndef DISABLE_SCTP 417 case IPPROTO_SCTP: { 418 CHECK_FCT(fd_sctp_get_local_ep(conn->cc_socket, local)); 419 } 420 break; 421 #endif /* DISABLE_SCTP */ 422 423 default: 424 CHECK_PARAMS(0); 425 } 426 } 427 428 if (remote) { 429 /* Check we have a full connection object, not a listening socket (with no remote) */ 430 CHECK_PARAMS( conn->cc_incoming ); 431 432 /* Retrieve the peer endpoint(s) of the connection */ 433 switch (conn->cc_proto) { 434 case IPPROTO_TCP: { 435 sSS ss; 436 socklen_t sl; 437 CHECK_FCT(fd_tcp_get_remote_ep(conn->cc_socket, &ss, &sl)); 438 CHECK_FCT(fd_ep_add_merge( remote, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY )); 439 } 440 break; 441 442 #ifndef DISABLE_SCTP 443 case IPPROTO_SCTP: { 444 CHECK_FCT(fd_sctp_get_remote_ep(conn->cc_socket, remote)); 445 } 446 break; 447 #endif /* DISABLE_SCTP */ 448 449 default: 450 CHECK_PARAMS(0); 451 } 452 } 453 454 return 0; 455 } 456 457 458 /* Get a string describing the remote peer address (ip address or fqdn) */ 459 char * fd_cnx_getremoteid(struct cnxctx * conn) 460 { 461 CHECK_PARAMS_DO( conn, return "" ); 462 return conn->cc_remid; 463 } 464 465 466 /**************************************/ 467 /* Use of a connection object */ 468 /**************************************/ 469 470 /* Receiver thread (TCP & noTLS) : incoming message is directly saved into the target queue */ 471 static void * rcvthr_notls_tcp(void * arg) 472 { 473 struct cnxctx * conn = arg; 474 475 TRACE_ENTRY("%p", arg); 476 477 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out); 478 ASSERT( conn->cc_proto == IPPROTO_TCP ); 479 ASSERT( conn->cc_tls == 0 ); 480 ASSERT( Target_Queue(conn) ); 481 482 /* Receive from a TCP connection: we have to rebuild the message boundaries */ 483 do { 484 uint8_t header[4]; 485 uint8_t * newmsg; 486 size_t length; 487 ssize_t ret = 0; 488 size_t received = 0; 489 490 do { 491 ret = recv(conn->cc_socket, &header[received], sizeof(header) - received, 0); 492 if (ret <= 0) { 493 CHECK_SYS_DO(ret, /* continue */); 494 goto error; /* Stop the thread, the recipient of the event will cleanup */ 495 } 496 497 received += ret; 498 } while (received < sizeof(header)); 499 500 length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3]; 501 502 /* Check the received word is a valid begining of a Diameter message */ 503 if ((header[0] != DIAMETER_VERSION) /* defined in <libfreeDiameter.h> */ 504 || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */ 505 /* The message is suspect */ 506 TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %g], assume disconnection", (int)header[0], length); 507 goto error; /* Stop the thread, the recipient of the event will cleanup */ 508 } 509 510 /* Ok, now we can really receive the data */ 511 CHECK_MALLOC_DO( newmsg = malloc( length ), goto error ); 512 memcpy(newmsg, header, sizeof(header)); 513 514 while (received < length) { 515 pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */ 516 ret = recv(conn->cc_socket, newmsg + received, length - received, 0); 517 pthread_cleanup_pop(0); 518 519 if (ret <= 0) { 520 CHECK_SYS_DO(ret, /* continue */); 521 free(newmsg); 522 goto error; /* Stop the thread, the recipient of the event will cleanup */ 523 } 524 received += ret; 525 } 526 527 /* We have received a complete message, send it */ 528 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */); 529 530 } while (conn->cc_loop); 531 532 out: 533 TRACE_DEBUG(FULL, "Thread terminated"); 534 return NULL; 535 error: 536 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */); 537 goto out; 538 } 539 540 #ifndef DISABLE_SCTP 541 /* Receiver thread (SCTP & noTLS) : incoming message is directly saved into cc_incoming, no need to care for the stream ID */ 542 static void * rcvthr_notls_sctp(void * arg) 543 { 544 struct cnxctx * conn = arg; 545 uint8_t * buf; 546 size_t bufsz; 547 int event; 548 549 TRACE_ENTRY("%p", arg); 550 551 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out); 552 ASSERT( conn->cc_proto == IPPROTO_SCTP ); 553 ASSERT( conn->cc_tls == 0 ); 554 ASSERT( Target_Queue(conn) ); 555 556 do { 557 CHECK_FCT_DO( fd_sctp_recvmeta(conn->cc_socket, NULL, &buf, &bufsz, &event), goto error ); 558 if (event == FDEVP_CNX_ERROR) { 559 goto error; 560 } 561 562 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), event, bufsz, buf), goto error ); 563 564 } while (conn->cc_loop); 565 566 out: 567 TRACE_DEBUG(FULL, "Thread terminated"); 568 return NULL; 569 error: 570 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */); 571 goto out; 572 } 573 #endif /* DISABLE_SCTP */ 574 575 /* Returns 0 on error, received data size otherwise (always >= 0) */ 576 static ssize_t fd_tls_recv_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz) 577 { 578 ssize_t ret; 579 again: 580 CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz), 581 { 582 switch (ret) { 583 case GNUTLS_E_REHANDSHAKE: 584 CHECK_GNUTLS_DO( ret = gnutls_handshake(session), 585 { 586 if (TRACE_BOOL(INFO)) { 587 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); 588 } 589 ret = 0; 590 goto end; 591 } ); 592 593 case GNUTLS_E_AGAIN: 594 case GNUTLS_E_INTERRUPTED: 595 goto again; 596 597 default: 598 TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error"); 599 ret = 0; 600 } 601 } ); 602 end: 603 return ret; 604 } 605 606 /* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */ 607 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session) 608 { 609 /* No guaranty that GnuTLS preserves the message boundaries, so we re-build it as in TCP */ 610 do { 611 uint8_t header[4]; 612 uint8_t * newmsg; 613 size_t length; 614 ssize_t ret = 0; 615 size_t received = 0; 616 617 do { 618 ret = fd_tls_recv_handle_error(conn, conn->cc_tls_para.session, &header[received], sizeof(header) - received); 619 if (ret == 0) { 620 /* The connection is closed */ 621 goto out; 622 } 623 received += ret; 624 } while (received < sizeof(header)); 625 626 length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3]; 627 628 /* Check the received word is a valid beginning of a Diameter message */ 629 if ((header[0] != DIAMETER_VERSION) /* defined in <libfreeDiameter.h> */ 630 || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */ 631 /* The message is suspect */ 632 TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %g], assume disconnection", (int)header[0], length); 633 goto out; 634 } 635 636 /* Ok, now we can really receive the data */ 637 CHECK_MALLOC( newmsg = malloc( length ) ); 638 memcpy(newmsg, header, sizeof(header)); 639 640 while (received < length) { 641 pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */ 642 ret = fd_tls_recv_handle_error(conn, conn->cc_tls_para.session, newmsg + received, length - received); 643 pthread_cleanup_pop(0); 644 645 if (ret == 0) { 646 free(newmsg); 647 goto out; /* Stop the thread, the recipient of the event will cleanup */ 648 } 649 received += ret; 650 } 651 652 /* We have received a complete message, send it */ 653 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */); 654 655 } while (1); 656 out: 657 return ENOTCONN; 658 } 659 660 /* Receiver thread (TLS & 1 stream SCTP or TCP) : gnutls directly handles the socket, save records into the target queue */ 661 static void * rcvthr_tls_single(void * arg) 662 { 663 struct cnxctx * conn = arg; 664 665 TRACE_ENTRY("%p", arg); 666 667 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto error); 668 ASSERT( conn->cc_tls == 1 ); 669 ASSERT( Target_Queue(conn) ); 670 671 CHECK_FCT_DO(fd_tls_rcvthr_core(conn, conn->cc_tls_para.session), /* continue */); 672 error: 673 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */); 674 TRACE_DEBUG(FULL, "Thread terminated"); 675 return NULL; 676 } 677 426 678 /* Start receving messages in clear (no TLS) on the connection */ 427 int fd_cnx_start_clear(struct cnxctx * conn) 428 { 429 430 TODO("..."); 431 return ENOTSUP; 679 int fd_cnx_start_clear(struct cnxctx * conn, int loop) 680 { 681 TRACE_ENTRY("%p %i", conn, loop); 682 683 CHECK_PARAMS( conn && Target_Queue(conn) && (!conn->cc_tls) && (!conn->cc_loop)); 684 685 /* Save the loop request */ 686 conn->cc_loop = loop; 687 688 /* Release resources in case of a previous call was already made */ 689 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */); 690 691 switch (conn->cc_proto) { 692 case IPPROTO_TCP: 693 /* Start the tcp_notls thread */ 694 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_notls_tcp, conn ) ); 695 break; 696 #ifndef DISABLE_SCTP 697 case IPPROTO_SCTP: 698 /* Start the tcp_notls thread */ 699 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_notls_sctp, conn ) ); 700 break; 701 #endif /* DISABLE_SCTP */ 702 default: 703 TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto); 704 return ENOTSUP; 705 } 706 707 return 0; 708 } 709 710 /* Prepare a gnutls session object for handshake */ 711 int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority) 712 { 713 /* Create the master session context */ 714 CHECK_GNUTLS_DO( gnutls_init (session, mode), return ENOMEM ); 715 716 /* Set the algorithm suite */ 717 if (priority) { 718 const char * errorpos; 719 CHECK_GNUTLS_DO( gnutls_priority_set_direct( *session, priority, &errorpos ), 720 { TRACE_DEBUG(INFO, "Error in priority string '%s' at position: '%s'\n", priority, errorpos); return EINVAL; } ); 721 } else { 722 CHECK_GNUTLS_DO( gnutls_priority_set( *session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL ); 723 } 724 725 /* Set the credentials of this side of the connection */ 726 CHECK_GNUTLS_DO( gnutls_credentials_set (*session, GNUTLS_CRD_CERTIFICATE, fd_g_config->cnf_sec_data.credentials), return EINVAL ); 727 728 /* Request the remote credentials as well */ 729 if (mode == GNUTLS_SERVER) { 730 gnutls_certificate_server_set_request (*session, GNUTLS_CERT_REQUIRE); 731 } 732 733 return 0; 432 734 } 433 735 … … 436 738 { 437 739 TRACE_ENTRY( "%p %d", conn, mode); 438 CHECK_PARAMS( conn && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER)) );740 CHECK_PARAMS( conn && (!conn->cc_tls) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) ); 439 741 440 742 /* Save the mode */ 441 743 conn->cc_tls_para.mode = mode; 442 443 /* Create the master session context */ 444 CHECK_GNUTLS_DO( gnutls_init (&conn->cc_tls_para.session, mode), return ENOMEM ); 445 446 /* Set the algorithm suite */ 447 TODO("Use overwrite priority if non NULL"); 448 CHECK_GNUTLS_DO( gnutls_priority_set( conn->cc_tls_para.session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL ); 449 450 /* Set the credentials of this side of the connection */ 451 CHECK_GNUTLS_DO( gnutls_credentials_set (conn->cc_tls_para.session, GNUTLS_CRD_CERTIFICATE, fd_g_config->cnf_sec_data.credentials), return EINVAL ); 452 453 /* Request the remote credentials as well */ 454 if (mode == GNUTLS_SERVER) { 455 gnutls_certificate_server_set_request (conn->cc_tls_para.session, GNUTLS_CERT_REQUIRE); 456 } 457 458 /* Set the socket info in the session */ 459 gnutls_transport_set_ptr (conn->cc_tls_para.session, (gnutls_transport_ptr_t) conn->cc_socket); 744 745 /* Cancel receiving thread if any -- it should already be terminated anyway, we just release the resources */ 746 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */); 747 748 /* Once TLS handshake is done, we don't stop after the first message */ 749 conn->cc_loop = 1; 750 751 /* Prepare the master session credentials and priority */ 752 CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, priority) ); 460 753 461 754 /* Special case: multi-stream TLS is not natively managed in GNU TLS, we use a wrapper library */ 462 if ( (conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) {463 #if ndef DISABLE_SCTP464 TODO("Initialize the SCTP TLS wrapper");465 TODO("Set the lowat, push and pull functions");755 if (conn->cc_sctp_para.pairs > 1) { 756 #ifdef DISABLE_SCTP 757 ASSERT(0); 758 CHECK_FCT( ENOTSUP ); 466 759 #else /* DISABLE_SCTP */ 467 ASSERT(0); 760 /* Initialize the wrapper, start the demux thread */ 761 CHECK_FCT( fd_sctps_init(conn) ); 468 762 #endif /* DISABLE_SCTP */ 763 } else { 764 /* Set the socket info in the session */ 765 gnutls_transport_set_ptr (conn->cc_tls_para.session, (gnutls_transport_ptr_t) conn->cc_socket); 469 766 } 470 767 … … 500 797 } 501 798 502 /* Other sessions in case of multi-stream SCTP are resumed from the master*/503 if ( (conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) {799 /* Multi-stream TLS: handshake other streams as well */ 800 if (conn->cc_sctp_para.pairs > 1) { 504 801 #ifndef DISABLE_SCTP 505 TODO("Init and resume all additional sessions from the master one."); 802 /* Resume all additional sessions from the master one. */ 803 CHECK_FCT(fd_sctps_handshake_others(conn, priority)); 804 805 /* Start decrypting the messages from all threads and queuing them in target queue */ 806 CHECK_FCT(fd_sctps_startthreads(conn)); 506 807 #endif /* DISABLE_SCTP */ 507 } 508 509 TODO("Start the connection state machine thread"); 808 } else { 809 /* Start decrypting the data */ 810 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_tls_single, conn ) ); 811 } 510 812 511 813 return 0; … … 515 817 int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size) 516 818 { 517 518 TODO("..."); 519 return ENOTSUP; 520 } 521 522 /* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */ 523 int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote) 524 { 525 TRACE_ENTRY("%p %p %p", conn, local, remote); 526 CHECK_PARAMS(conn); 527 528 if (local) { 529 /* Retrieve the local endpoint(s) of the connection */ 530 switch (conn->cc_proto) { 531 case IPPROTO_TCP: { 532 sSS ss; 533 socklen_t sl; 534 CHECK_FCT(fd_tcp_get_local_ep(conn->cc_socket, &ss, &sl)); 535 CHECK_FCT(fd_ep_add_merge( local, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY)); 536 } 819 TRACE_ENTRY("%p %p %p", conn, cert_list, cert_list_size); 820 CHECK_PARAMS( conn && (conn->cc_tls) && cert_list && cert_list_size ); 821 822 /* This function only works for X.509 certificates. */ 823 CHECK_PARAMS( gnutls_certificate_type_get (conn->cc_tls_para.session) == GNUTLS_CRT_X509 ); 824 825 *cert_list = gnutls_certificate_get_peers (conn->cc_tls_para.session, cert_list_size); 826 if (*cert_list == NULL) { 827 TRACE_DEBUG(INFO, "No certificate was provided by remote peer / an error occurred."); 828 return EINVAL; 829 } 830 831 TRACE_DEBUG( FULL, "Remote peer provided %d certificates.\n", *cert_list_size); 832 833 return 0; 834 } 835 836 /* Receive next message. if timeout is not NULL, wait only until timeout. This function only pulls from a queue, mgr thread is filling that queue aynchrounously. */ 837 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len) 838 { 839 int ev; 840 size_t ev_sz; 841 void * ev_data; 842 843 TRACE_ENTRY("%p %p %p %p", conn, timeout, buf, len); 844 CHECK_PARAMS(conn && (conn->cc_socket > 0) && buf && len); 845 CHECK_PARAMS(conn->cc_rcvthr != (pthread_t)NULL); 846 CHECK_PARAMS(conn->cc_alt == NULL); 847 848 /* Now, pull the first event */ 849 get_next: 850 if (timeout) { 851 CHECK_FCT( fd_event_timedget(conn->cc_incoming, timeout, FDEVP_PSM_TIMEOUT, &ev, &ev_sz, &ev_data) ); 852 } else { 853 CHECK_FCT( fd_event_get(conn->cc_incoming, &ev, &ev_sz, &ev_data) ); 854 } 855 856 switch (ev) { 857 case FDEVP_CNX_MSG_RECV: 858 /* We got one */ 859 *len = ev_sz; 860 *buf = ev_data; 861 return 0; 862 863 case FDEVP_PSM_TIMEOUT: 864 TRACE_DEBUG(FULL, "Timeout event received"); 865 return ETIMEDOUT; 866 867 case FDEVP_CNX_EP_CHANGE: 868 /* We ignore this event */ 869 goto get_next; 870 871 case FDEVP_CNX_ERROR: 872 TRACE_DEBUG(FULL, "Received ERROR event on the connection"); 873 return ENOTCONN; 874 } 875 876 TRACE_DEBUG(INFO, "Received unexpected event %d (%s)", ev, fd_pev_str(ev)); 877 return EINVAL; 878 } 879 880 /* Set an alternate FIFO list to send FDEVP_CNX_* events to */ 881 int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo) 882 { 883 TRACE_ENTRY( "%p %p", conn, alt_fifo ); 884 CHECK_PARAMS( conn && alt_fifo && conn->cc_incoming ); 885 886 /* The magic function does it all */ 887 CHECK_FCT( fd_fifo_move( &conn->cc_incoming, alt_fifo, &conn->cc_alt ) ); 888 889 return 0; 890 } 891 892 /* Send function when no multi-stream is involved, or sending on stream #0 (send() always use stream 0)*/ 893 static int send_simple(struct cnxctx * conn, unsigned char * buf, size_t len) 894 { 895 ssize_t ret; 896 size_t sent = 0; 897 TRACE_ENTRY("%p %p %g", conn, buf, len); 898 do { 899 if (conn->cc_tls) { 900 CHECK_GNUTLS_DO( ret = gnutls_record_send (conn->cc_tls_para.session, buf + sent, len - sent), return ENOTCONN ); 901 } else { 902 CHECK_SYS( ret = send(conn->cc_socket, buf + sent, len - sent, 0) ); /* better to replace with sendmsg for atomic sending? */ 903 } 904 sent += ret; 905 } while ( sent < len ); 906 return 0; 907 } 908 909 /* Send a message -- this is synchronous -- and we assume it's never called by several threads at the same time, so we don't protect. */ 910 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len) 911 { 912 TRACE_ENTRY("%p %p %g", conn, buf, len); 913 914 CHECK_PARAMS(conn && (conn->cc_socket > 0) && buf && len); 915 916 TRACE_DEBUG(FULL, "Sending %gb %sdata on connection %s", len, conn->cc_tls ? "TLS-protected ":"", conn->cc_id); 917 918 switch (conn->cc_proto) { 919 case IPPROTO_TCP: 920 CHECK_FCT( send_simple(conn, buf, len) ); 537 921 break; 538 539 #ifndef DISABLE_SCTP 540 case IPPROTO_SCTP: { 541 CHECK_FCT(fd_sctp_get_local_ep(conn->cc_socket, local)); 542 } 543 break; 544 #endif /* DISABLE_SCTP */ 545 546 default: 547 CHECK_PARAMS(0); 548 } 549 } 550 551 if (remote) { 552 /* Check we have a full connection object, not a listening socket (with no remote) */ 553 CHECK_PARAMS( conn->cc_events ); 554 555 /* Retrieve the peer endpoint(s) of the connection */ 556 switch (conn->cc_proto) { 557 case IPPROTO_TCP: { 558 sSS ss; 559 socklen_t sl; 560 CHECK_FCT(fd_tcp_get_remote_ep(conn->cc_socket, &ss, &sl)); 561 CHECK_FCT(fd_ep_add_merge( remote, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY )); 562 } 563 break; 564 565 #ifndef DISABLE_SCTP 566 case IPPROTO_SCTP: { 567 CHECK_FCT(fd_sctp_get_remote_ep(conn->cc_socket, remote)); 568 } 569 break; 570 #endif /* DISABLE_SCTP */ 571 572 default: 573 CHECK_PARAMS(0); 574 } 575 } 576 922 923 #ifndef DISABLE_SCTP 924 case IPPROTO_SCTP: { 925 int multistr = 0; 926 927 if ((conn->cc_sctp_para.str_out > 1) && ((! conn->cc_tls) || (conn->cc_sctp_para.pairs > 1))) { 928 /* Update the id of the stream we will send this message on */ 929 conn->cc_sctp_para.next += 1; 930 conn->cc_sctp_para.next %= (conn->cc_tls ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out); 931 multistr = 1; 932 } 933 934 if ((!multistr) || (conn->cc_sctp_para.next == 0)) { 935 CHECK_FCT( send_simple(conn, buf, len) ); 936 } else { 937 if (!conn->cc_tls) { 938 CHECK_FCT( fd_sctp_sendstr(conn->cc_socket, conn->cc_sctp_para.next, buf, len) ); 939 } else { 940 /* push the record to the appropriate session */ 941 ssize_t ret; 942 size_t sent = 0; 943 ASSERT(conn->cc_sctps_data.array != NULL); 944 do { 945 CHECK_GNUTLS_DO( ret = gnutls_record_send (conn->cc_sctps_data.array[conn->cc_sctp_para.next - 1].session, buf + sent, len - sent), { TODO("Handle error (re-handshake, etc.."); return ENOTCONN; } ); 946 sent += ret; 947 } while ( sent < len ); 948 } 949 } 950 } 951 break; 952 #endif /* DISABLE_SCTP */ 953 954 default: 955 TRACE_DEBUG(INFO, "Unknwon protocol: %d", conn->cc_proto); 956 return ENOTSUP; /* or EINVAL... */ 957 } 958 577 959 return 0; 578 960 } 579 961 580 962 581 /* Get a string describing the remote peer address (ip address or fqdn) */ 582 char * fd_cnx_getremoteid(struct cnxctx * conn) 583 { 584 CHECK_PARAMS_DO( conn, return "" ); 585 return conn->cc_remid; 586 } 587 588 589 /* Receive next message. if timeout is not NULL, wait only until timeout */ 590 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len) 591 { 592 593 TODO("..."); 594 return ENOTSUP; 595 } 596 597 /* Set / reset alternate FIFO list to send FDEVP_CNX_MSG_RECV to when message is received */ 598 int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo) 599 { 600 TRACE_ENTRY( "%p %p", conn, alt_fifo ); 601 CHECK_PARAMS( conn ); 602 603 /* Let's cross fingers that there is no race condition here... */ 604 conn->cc_alt = alt_fifo; 605 606 return 0; 607 } 608 609 /* Send a message */ 610 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len) 611 { 612 613 TODO("..."); 614 return ENOTSUP; 615 } 616 963 /**************************************/ 964 /* Destruction of connection */ 965 /**************************************/ 617 966 618 967 /* Destroy a conn structure, and shutdown the socket */ … … 623 972 CHECK_PARAMS_DO(conn, return); 624 973 625 TODO("End TLS session(s) if started"); 626 627 TODO("Stop manager thread if running"); 974 /* In case of TLS, stop receiver thread, then close properly the gnutls session */ 975 if ((conn->cc_tls) && (conn->cc_sctp_para.pairs > 1)) { 976 #ifndef DISABLE_SCTP 977 /* Multi-stream TLS: Stop all decipher threads, but not the demux thread */ 978 fd_sctps_stopthreads(conn); 979 #endif /* DISABLE_SCTP */ 980 } else { 981 /* Stop the decoding thread */ 982 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ ); 983 } 984 985 /* Terminate properly the TLS session(s) */ 986 if (conn->cc_tls) { 987 /* Master session */ 988 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_RDWR), /* Continue */ ); 989 gnutls_deinit(conn->cc_tls_para.session); 990 991 #ifndef DISABLE_SCTP 992 if (conn->cc_sctp_para.pairs > 1) { 993 /* Multi-stream TLS: destroy the wrapper and stop the demux thread */ 994 fd_sctps_destroy(conn); 995 } 996 #endif /* DISABLE_SCTP */ 997 998 } 628 999 629 1000 /* Shut the connection down */ … … 632 1003 } 633 1004 634 TODO("Empty FIFO queues"); 635 636 /* Destroy FIFO lists */ 637 if (conn->cc_events) 638 CHECK_FCT_DO( fd_fifo_del ( &conn->cc_events ), /* continue */ ); 639 if (conn->cc_incoming) 640 CHECK_FCT_DO( fd_fifo_del ( &conn->cc_incoming ), /* continue */ ); 1005 /* Empty and destroy FIFO list */ 1006 if (conn->cc_incoming) { 1007 fd_event_destroy( &conn->cc_incoming, free ); 1008 } 641 1009 642 1010 /* Free the object */ -
freeDiameter/fD.h
r24 r25 152 152 enum { 153 153 /* Dump all info about this peer in the debug log */ 154 FDEVP_DUMP_ALL = 2000154 FDEVP_DUMP_ALL = 1500 155 155 156 156 /* request to terminate this peer : disconnect, requeue all messages */ 157 157 ,FDEVP_TERMINATE 158 158 159 /* A connection object has received a message -- stored in event->data*/159 /* A connection object has received a message. */ 160 160 ,FDEVP_CNX_MSG_RECV 161 162 /* A connection object has encountered an error (disconnected). */ 163 ,FDEVP_CNX_ERROR 164 165 /* Endpoints of a connection have been changed (multihomed SCTP). */ 166 ,FDEVP_CNX_EP_CHANGE 161 167 162 168 /* A message was received in the peer */ … … 210 216 struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list); 211 217 char * fd_cnx_getid(struct cnxctx * conn); 212 int fd_cnx_start_clear(struct cnxctx * conn );218 int fd_cnx_start_clear(struct cnxctx * conn, int loop); 213 219 int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority); 214 220 int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size); … … 220 226 void fd_cnx_destroy(struct cnxctx * conn); 221 227 222 /* TCP */223 int fd_tcp_create_bind_server( int * sock, sSA * sa, socklen_t salen );224 int fd_tcp_listen( int sock );225 int fd_tcp_client( int *sock, sSA * sa, socklen_t salen );226 int fd_tcp_get_local_ep(int sock, sSS * ss, socklen_t *sl);227 int fd_tcp_get_remote_ep(int sock, sSS * ss, socklen_t *sl);228 229 /* SCTP */230 #ifndef DISABLE_SCTP231 int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port );232 int fd_sctp_listen( int sock );233 int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list );234 int fd_sctp_get_local_ep(int sock, struct fd_list * list);235 int fd_sctp_get_remote_ep(int sock, struct fd_list * list);236 int fd_sctp_get_str_info( int sock, int *in, int *out, sSS *primary );237 238 #endif /* DISABLE_SCTP */239 240 241 228 242 229 #endif /* _FD_H */ -
freeDiameter/main.c
r23 r25 117 117 TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized."); 118 118 while (1) { 119 int code; 120 CHECK_FCT_DO( fd_event_get(fd_g_config->cnf_main_ev, &code, NULL), break );119 int code; size_t sz; void * data; 120 CHECK_FCT_DO( fd_event_get(fd_g_config->cnf_main_ev, &code, &sz, &data), break ); 121 121 switch (code) { 122 122 case FDEV_DUMP_DICT: … … 339 339 340 340 TRACE_DEBUG(INFO, "Received signal %s (%d), exiting", SIGNALSTR(sig), sig); 341 CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), exit(2) );341 CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), exit(2) ); 342 342 return NULL; 343 343 } -
freeDiameter/p_expiry.c
r22 r25 87 87 TRACE_DEBUG(INFO, "An error occurred in peers module! GC thread is terminating..."); 88 88 ASSERT(0); 89 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );89 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 90 90 return NULL; 91 91 } … … 132 132 /* Now, the first peer in the list is expired; signal it */ 133 133 fd_list_unlink( &first->p_expiry ); 134 CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, NULL), goto error );134 CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, 0, NULL), goto error ); 135 135 136 136 } while (1); … … 140 140 TRACE_DEBUG(INFO, "An error occurred in peers module! Expiry thread is terminating..."); 141 141 ASSERT(0); 142 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );142 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 143 143 return NULL; 144 144 } -
freeDiameter/p_psm.c
r22 r25 58 58 case_str(FDEVP_TERMINATE); 59 59 case_str(FDEVP_CNX_MSG_RECV); 60 case_str(FDEVP_CNX_ERROR); 61 case_str(FDEVP_CNX_EP_CHANGE); 60 62 case_str(FDEVP_MSG_INCOMING); 61 63 case_str(FDEVP_PSM_TIMEOUT); … … 126 128 } 127 129 128 /* Wait for the next event in the PSM, or timeout */129 static int psm_ev_timedget(struct fd_peer * peer, int *code, void ** data)130 {131 struct fd_event * ev;132 int ret = 0;133 134 TRACE_ENTRY("%p %p %p", peer, code, data);135 136 ret = fd_fifo_timedget(peer->p_events, &ev, &peer->p_psm_timer);137 if (ret == ETIMEDOUT) {138 *code = FDEVP_PSM_TIMEOUT;139 *data = NULL;140 } else {141 CHECK_FCT( ret );142 *code = ev->code;143 *data = ev->data;144 free(ev);145 }146 147 return 0;148 }149 150 130 /* The state machine thread (controler) */ 151 131 static void * p_psm_th( void * arg ) … … 154 134 int created_started = started; 155 135 int event; 136 size_t ev_sz; 156 137 void * ev_data; 157 138 … … 182 163 psm_loop: 183 164 /* Get next event */ 184 CHECK_FCT_DO( psm_ev_timedget(peer, &event, &ev_data), goto psm_end );185 TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p )\t'%s'",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,%g)\t'%s'", 186 167 STATE_STR(peer->p_hdr.info.pi_state), 187 fd_pev_str(event), ev_data, 168 fd_pev_str(event), ev_data, ev_sz, 188 169 peer->p_hdr.info.pi_diamid); 189 170 … … 272 253 273 254 if (peer->p_hdr.info.pi_state != STATE_ZOMBIE) { 274 CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, NULL) );255 CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) ); 275 256 } else { 276 257 TRACE_DEBUG(FULL, "Peer '%s' was already terminated", peer->p_hdr.info.pi_diamid); -
freeDiameter/sctp.c
r24 r25 35 35 36 36 #include "fD.h" 37 #include "cnxctx.h" 38 37 39 #include <netinet/sctp.h> 38 40 #include <sys/uio.h> 41 42 /* Size of buffer to receive ancilliary data. May need to be enlarged if more sockopt are set... */ 43 #ifndef CMSG_BUF_LEN 44 #define CMSG_BUF_LEN 1024 45 #endif /* CMSG_BUF_LEN */ 39 46 40 47 /* Pre-binding socket options -- # streams read in config */ … … 744 751 745 752 /* Retrieve streams information from a connected association -- optionaly provide the primary address */ 746 int fd_sctp_get_str_info( int sock, int *in, int *out, sSS *primary )753 int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary ) 747 754 { 748 755 struct sctp_status status; … … 776 783 #endif /* DEBUG_SCTP */ 777 784 778 *in = (int)status.sstat_instrms;779 *out = (int)status.sstat_outstrms;785 *in = status.sstat_instrms; 786 *out = status.sstat_outstrms; 780 787 781 788 if (primary) … … 893 900 } 894 901 902 /* Send a buffer over a specified stream */ 903 int fd_sctp_sendstr(int sock, uint16_t strid, uint8_t * buf, size_t len) 904 { 905 struct msghdr mhdr; 906 struct iovec iov; 907 struct { 908 struct cmsghdr hdr; 909 struct sctp_sndrcvinfo sndrcv; 910 } anci; 911 ssize_t ret; 912 913 TRACE_ENTRY("%d %hu %p %g", sock, strid, buf, len); 914 915 memset(&mhdr, 0, sizeof(mhdr)); 916 memset(&iov, 0, sizeof(iov)); 917 memset(&anci, 0, sizeof(anci)); 918 919 /* IO Vector: message data */ 920 iov.iov_base = buf; 921 iov.iov_len = len; 922 923 /* Anciliary data: specify SCTP stream */ 924 anci.hdr.cmsg_len = sizeof(anci); 925 anci.hdr.cmsg_level = IPPROTO_SCTP; 926 anci.hdr.cmsg_type = SCTP_SNDRCV; 927 anci.sndrcv.sinfo_stream = strid; 928 /* note : we could store other data also, for example in .sinfo_ppid for remote peer or in .sinfo_context for errors. */ 929 930 /* We don't use mhdr.msg_name here; it could be used to specify an address different from the primary */ 931 932 mhdr.msg_iov = &iov; 933 mhdr.msg_iovlen = 1; 934 935 mhdr.msg_control = &anci; 936 mhdr.msg_controllen = sizeof(anci); 937 938 #ifdef DEBUG_SCTP 939 TRACE_DEBUG(FULL, "Sending %db data on stream %hu of socket %d", len, strid, sock); 940 #endif /* DEBUG_SCTP */ 941 942 CHECK_SYS( ret = sendmsg(sock, &mhdr, 0) ); 943 ASSERT( ret == len ); /* There should not be partial delivery with sendmsg... */ 944 945 return 0; 946 } 947 948 /* Receive the next data from the socket, or next notification */ 949 int fd_sctp_recvmeta(int sock, uint16_t * strid, uint8_t ** buf, size_t * len, int *event) 950 { 951 ssize_t ret = 0; 952 struct msghdr mhdr; 953 char ancidata[ CMSG_BUF_LEN ]; 954 struct iovec iov; 955 uint8_t *data = NULL; 956 size_t bufsz = 0, datasize = 0; 957 size_t mempagesz = sysconf(_SC_PAGESIZE); /* We alloc buffer by memory pages for efficiency */ 958 959 TRACE_ENTRY("%d %p %p %p %p", sock, strid, buf, len, event); 960 CHECK_PARAMS( (sock > 0) && buf && len && event ); 961 962 /* Cleanup out parameters */ 963 *buf = NULL; 964 *len = 0; 965 *event = 0; 966 967 /* Prepare header for receiving message */ 968 memset(&mhdr, 0, sizeof(mhdr)); 969 mhdr.msg_iov = &iov; 970 mhdr.msg_iovlen = 1; 971 mhdr.msg_control = &ancidata; 972 mhdr.msg_controllen = sizeof(ancidata); 973 974 /* We will loop while all data is not received. */ 975 incomplete: 976 if (datasize == bufsz) { 977 /* The buffer is full, enlarge it */ 978 bufsz += mempagesz; 979 CHECK_MALLOC( data = realloc(data, bufsz) ); 980 } 981 /* the new data will be received following the preceding */ 982 memset(&iov, 0, sizeof(iov)); 983 iov.iov_base = data + datasize ; 984 iov.iov_len = bufsz - datasize; 985 986 /* Receive data from the socket */ 987 pthread_cleanup_push(free, data); 988 ret = recvmsg(sock, &mhdr, 0); 989 pthread_cleanup_pop(0); 990 991 /* Handle errors */ 992 if (ret <= 0) { /* Socket is closed, or an error occurred */ 993 CHECK_SYS_DO(ret, /* to log in case of error */); 994 free(data); 995 *event = FDEVP_CNX_ERROR; 996 return 0; 997 } 998 999 /* Update the size of data we received */ 1000 datasize += ret; 1001 1002 /* SCTP provides an indication when we received a full record; loop if it is not the case */ 1003 if ( ! (mhdr.msg_flags & MSG_EOR) ) { 1004 goto incomplete; 1005 } 1006 1007 /* Handle the case where the data received is a notification */ 1008 if (mhdr.msg_flags & MSG_NOTIFICATION) { 1009 union sctp_notification * notif = (union sctp_notification *) data; 1010 1011 switch (notif->sn_header.sn_type) { 1012 1013 case SCTP_ASSOC_CHANGE: 1014 #ifdef DEBUG_SCTP 1015 TRACE_DEBUG(FULL, "Received SCTP_ASSOC_CHANGE notification"); 1016 TRACE_DEBUG(FULL, " state : %hu", notif->sn_assoc_change.sac_state); 1017 TRACE_DEBUG(FULL, " error : %hu", notif->sn_assoc_change.sac_error); 1018 TRACE_DEBUG(FULL, " instr : %hu", notif->sn_assoc_change.sac_inbound_streams); 1019 TRACE_DEBUG(FULL, " outstr : %hu", notif->sn_assoc_change.sac_outbound_streams); 1020 #endif /* DEBUG_SCTP */ 1021 1022 *event = FDEVP_CNX_EP_CHANGE; 1023 break; 1024 1025 case SCTP_PEER_ADDR_CHANGE: 1026 #ifdef DEBUG_SCTP 1027 TRACE_DEBUG(FULL, "Received SCTP_PEER_ADDR_CHANGE notification"); 1028 TRACE_DEBUG_sSA(FULL, " intf_change : ", &(notif->sn_paddr_change.spc_aaddr), NI_NUMERICHOST | NI_NUMERICSERV, "" ); 1029 TRACE_DEBUG(FULL, " state : %d", notif->sn_paddr_change.spc_state); 1030 TRACE_DEBUG(FULL, " error : %d", notif->sn_paddr_change.spc_error); 1031 #endif /* DEBUG_SCTP */ 1032 1033 *event = FDEVP_CNX_EP_CHANGE; 1034 break; 1035 1036 case SCTP_SEND_FAILED: 1037 #ifdef DEBUG_SCTP 1038 TRACE_DEBUG(FULL, "Received SCTP_SEND_FAILED notification"); 1039 TRACE_DEBUG(FULL, " len : %hu", notif->sn_send_failed.ssf_length); 1040 TRACE_DEBUG(FULL, " err : %d", notif->sn_send_failed.ssf_error); 1041 #endif /* DEBUG_SCTP */ 1042 1043 *event = FDEVP_CNX_ERROR; 1044 break; 1045 1046 case SCTP_REMOTE_ERROR: 1047 #ifdef DEBUG_SCTP 1048 TRACE_DEBUG(FULL, "Received SCTP_REMOTE_ERROR notification"); 1049 TRACE_DEBUG(FULL, " err : %hu", ntohs(notif->sn_remote_error.sre_error)); 1050 TRACE_DEBUG(FULL, " len : %hu", ntohs(notif->sn_remote_error.sre_length)); 1051 #endif /* DEBUG_SCTP */ 1052 1053 *event = FDEVP_CNX_ERROR; 1054 break; 1055 1056 case SCTP_SHUTDOWN_EVENT: 1057 #ifdef DEBUG_SCTP 1058 TRACE_DEBUG(FULL, "Received SCTP_SHUTDOWN_EVENT notification"); 1059 #endif /* DEBUG_SCTP */ 1060 1061 *event = FDEVP_CNX_ERROR; 1062 break; 1063 1064 default: 1065 TRACE_DEBUG(FULL, "Received unknown notification %d, assume error", notif->sn_header.sn_type); 1066 *event = FDEVP_CNX_ERROR; 1067 } 1068 1069 free(data); 1070 return 0; 1071 } 1072 1073 /* From this point, we have received a message */ 1074 *event = FDEVP_CNX_MSG_RECV; 1075 *buf = data; 1076 *len = datasize; 1077 1078 if (strid) { 1079 struct cmsghdr *hdr; 1080 struct sctp_sndrcvinfo *sndrcv; 1081 1082 /* Handle the anciliary data */ 1083 for (hdr = CMSG_FIRSTHDR(&mhdr); hdr; hdr = CMSG_NXTHDR(&mhdr, hdr)) { 1084 1085 /* We deal only with anciliary data at SCTP level */ 1086 if (hdr->cmsg_level != IPPROTO_SCTP) { 1087 TRACE_DEBUG(FULL, "Received some anciliary data at level %d, skipped", hdr->cmsg_level); 1088 continue; 1089 } 1090 1091 /* Also only interested in SCTP_SNDRCV message for the moment */ 1092 if (hdr->cmsg_type != SCTP_SNDRCV) { 1093 TRACE_DEBUG(FULL, "Anciliary block IPPROTO_SCTP / %d, skipped", hdr->cmsg_type); 1094 continue; 1095 } 1096 1097 sndrcv = (struct sctp_sndrcvinfo *) CMSG_DATA(hdr); 1098 #ifdef DEBUG_SCTP 1099 TRACE_DEBUG(FULL, "Anciliary block IPPROTO_SCTP / SCTP_SNDRCV"); 1100 TRACE_DEBUG(FULL, " sinfo_stream : %hu", sndrcv->sinfo_stream); 1101 TRACE_DEBUG(FULL, " sinfo_ssn : %hu", sndrcv->sinfo_ssn); 1102 TRACE_DEBUG(FULL, " sinfo_flags : %hu", sndrcv->sinfo_flags); 1103 /* TRACE_DEBUG(FULL, " sinfo_pr_policy : %hu", sndrcv->sinfo_pr_policy); */ 1104 TRACE_DEBUG(FULL, " sinfo_ppid : %u" , sndrcv->sinfo_ppid); 1105 TRACE_DEBUG(FULL, " sinfo_context : %u" , sndrcv->sinfo_context); 1106 /* TRACE_DEBUG(FULL, " sinfo_pr_value : %u" , sndrcv->sinfo_pr_value); */ 1107 TRACE_DEBUG(FULL, " sinfo_tsn : %u" , sndrcv->sinfo_tsn); 1108 TRACE_DEBUG(FULL, " sinfo_cumtsn : %u" , sndrcv->sinfo_cumtsn); 1109 #endif /* DEBUG_SCTP */ 1110 1111 *strid = sndrcv->sinfo_stream; 1112 } 1113 } 1114 1115 return 0; 1116 } -
freeDiameter/server.c
r24 r25 120 120 } 121 121 } else { 122 CHECK_FCT_DO( fd_cnx_start_clear(c->conn ), goto cleanup );122 CHECK_FCT_DO( fd_cnx_start_clear(c->conn, 0), goto cleanup ); 123 123 } 124 124 … … 135 135 TODO("Send event to the peer"); 136 136 137 TODO("(later) handshake or start_clear(.., 1)"); 137 138 /* The end */ 138 139 cleanup: … … 152 153 153 154 fatal_error: /* This has effect to terminate the daemon */ 154 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );155 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 155 156 return NULL; 156 157 } … … 198 199 /* Send error signal to the daemon */ 199 200 TRACE_DEBUG(INFO, "An error occurred in server module! Thread is terminating..."); 200 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );201 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 201 202 202 203 return NULL; -
freeDiameter/tcp.c
r24 r25 35 35 36 36 #include "fD.h" 37 #include "cnxctx.h" 38 37 39 #include <netinet/tcp.h> 38 40 #include <netinet/ip6.h> -
include/freeDiameter/freeDiameter.h
r24 r25 152 152 struct fd_event { 153 153 int code; /* codespace depends on the queue */ 154 size_t size; 154 155 void *data; 155 156 }; 156 157 157 static __inline__ int fd_event_send(struct fifo *queue, int code, void * data) 158 { 159 struct fd_event * ev; 160 CHECK_MALLOC( ev = malloc(sizeof(struct fd_event)) ); 161 ev->code = code; 162 ev->data = data; 163 CHECK_FCT( fd_fifo_post(queue, &ev) ); 164 return 0; 165 } 166 static __inline__ int fd_event_get(struct fifo *queue, int *code, void ** data) 167 { 168 struct fd_event * ev; 169 CHECK_FCT( fd_fifo_get(queue, &ev) ); 170 if (code) 171 *code = ev->code; 172 if (data) 173 *data = ev->data; 174 free(ev); 175 return 0; 176 } 177 178 /* Events codespace for fd_g_config->cnf_main_ev */ 158 /* Daemon's codespace: 1000->1999 */ 179 159 enum { 180 FDEV_TERMINATE 160 FDEV_TERMINATE = 1000 /* request to terminate */ 181 161 ,FDEV_DUMP_DICT /* Dump the content of the dictionary */ 182 162 ,FDEV_DUMP_EXT /* Dump state of extensions */ … … 186 166 ,FDEV_DUMP_PEERS /* Dump the list of peers */ 187 167 }; 168 169 static __inline__ int fd_event_send(struct fifo *queue, int code, size_t datasz, void * data) 170 { 171 struct fd_event * ev; 172 CHECK_MALLOC( ev = malloc(sizeof(struct fd_event)) ); 173 ev->code = code; 174 ev->size = datasz; 175 ev->data = data; 176 CHECK_FCT( fd_fifo_post(queue, &ev) ); 177 return 0; 178 } 179 static __inline__ int fd_event_get(struct fifo *queue, int *code, size_t *datasz, void ** data) 180 { 181 struct fd_event * ev; 182 CHECK_FCT( fd_fifo_get(queue, &ev) ); 183 if (code) 184 *code = ev->code; 185 if (datasz) 186 *datasz = ev->size; 187 if (data) 188 *data = ev->data; 189 free(ev); 190 return 0; 191 } 192 static __inline__ int fd_event_timedget(struct fifo *queue, struct timespec * timeout, int timeoutcode, int *code, size_t *datasz, void ** data) 193 { 194 struct fd_event * ev; 195 int ret = 0; 196 ret = fd_fifo_timedget(queue, &ev, timeout); 197 if (ret == ETIMEDOUT) { 198 if (code) 199 *code = timeoutcode; 200 if (datasz) 201 *datasz = 0; 202 if (data) 203 *data = NULL; 204 } else { 205 CHECK_FCT( ret ); 206 if (code) 207 *code = ev->code; 208 if (datasz) 209 *datasz = ev->size; 210 if (data) 211 *data = ev->data; 212 free(ev); 213 } 214 return 0; 215 } 216 static __inline__ void fd_event_destroy(struct fifo **queue, void (*free_cb)(void * data)) 217 { 218 struct fd_event * ev; 219 /* Purge all events, and free the associated data if any */ 220 while (fd_fifo_tryget( *queue, &ev ) == 0) { 221 (*free_cb)(ev->data); 222 free(ev); 223 } 224 CHECK_FCT_DO( fd_fifo_del(queue), /* continue */ ); 225 return ; 226 } 188 227 const char * fd_ev_str(int event); /* defined in freeDiameter/main.c */ 189 228 -
include/freeDiameter/libfreeDiameter.h
r24 r25 427 427 428 428 429 /* Trace a binary buffer content */ 430 #define TRACE_DEBUG_BUFFER(level, prefix, buf, bufsz, suffix ) { \ 431 if ( TRACE_BOOL(level) ) { \ 432 int __i; \ 433 size_t __sz = (size_t)(bufsz); \ 434 uint8_t * __buf = (uint8_t *)(buf); \ 435 char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed"); \ 436 fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n" \ 437 "\t%s|%*s" prefix , \ 438 __thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,\ 439 (level < FULL)?"@":" ",level, ""); \ 440 for (__i = 0; __i < __sz; __i++) { \ 441 fd_log_debug("%02.2hhx", __buf[__i]); \ 442 } \ 443 fd_log_debug(suffix "\n"); \ 444 } \ 445 } 446 447 448 429 449 /*============================================================*/ 430 450 /* THREADS */ … … 508 528 void fd_list_insert_after ( struct fd_list * ref, struct fd_list * item ); 509 529 void fd_list_insert_before ( struct fd_list * ref, struct fd_list * item ); 530 531 /* Move a list at the end of another */ 532 void fd_list_move_end(struct fd_list * ref, struct fd_list * senti); 510 533 511 534 /* Insert an item in an ordered list -- ordering function provided. If duplicate object found, EEXIST and it is returned in ref_duplicate */ … … 2385 2408 2386 2409 /* 2410 * FUNCTION: fd_fifo_move 2411 * 2412 * PARAMETERS: 2413 * old : Location of a FIFO that is to be emptied and deleted. 2414 * new : A FIFO that will receive the old data. 2415 * loc_update : if non NULL, a place to store the pointer to new FIFO atomically with the move. 2416 * 2417 * DESCRIPTION: 2418 * Delete a queue and move its content to another one atomically. 2419 * 2420 * RETURN VALUE: 2421 * 0 : The queue has been destroyed successfully. 2422 * EINVAL : A parameter is invalid. 2423 */ 2424 int fd_fifo_move ( struct fifo ** old, struct fifo * new, struct fifo ** loc_update ); 2425 2426 /* 2387 2427 * FUNCTION: fd_fifo_length 2388 2428 * -
libfreeDiameter/fifo.c
r21 r25 150 150 CHECK_POSIX( pthread_mutex_lock( &q->mtx ) ); 151 151 152 /* Ok, now invalidate the queue */153 q->eyec = 0xdead;154 155 152 if ((q->count != 0) || (q->data != NULL)) { 156 153 TRACE_DEBUG(INFO, "The queue cannot be destroyed (%d, %p)", q->count, q->data); … … 158 155 return EINVAL; 159 156 } 157 158 /* Ok, now invalidate the queue */ 159 q->eyec = 0xdead; 160 160 161 161 while (q->thrs) { … … 179 179 free(q); 180 180 *queue = NULL; 181 182 return 0; 183 } 184 185 /* Move the content of old into new, and update loc_update atomically */ 186 int fd_fifo_move ( struct fifo ** old, struct fifo * new, struct fifo ** loc_update ) 187 { 188 struct fifo * q; 189 int loops = 0; 190 191 TRACE_ENTRY("%p %p %p", old, new, loc_update); 192 CHECK_PARAMS( old && CHECK_FIFO( *old ) && CHECK_FIFO( new )); 193 194 q = *old; 195 CHECK_PARAMS( ! q->data ); 196 if (new->high) { 197 TODO("Implement support for thresholds in fd_fifo_move..."); 198 } 199 200 /* Update loc_update */ 201 *old = NULL; 202 if (loc_update) 203 *loc_update = new; 204 205 /* Lock the queues */ 206 CHECK_POSIX( pthread_mutex_lock( &q->mtx ) ); 207 CHECK_POSIX( pthread_mutex_lock( &new->mtx ) ); 208 209 /* Any waiting thread on the old queue returns an error */ 210 q->eyec = 0xdead; 211 while (q->thrs) { 212 CHECK_POSIX( pthread_cond_signal(&q->cond) ); 213 CHECK_POSIX( pthread_mutex_unlock( &q->mtx )); 214 pthread_yield(); 215 CHECK_POSIX( pthread_mutex_lock( &q->mtx ) ); 216 ASSERT( ++loops < 10 ); /* detect infinite loops */ 217 } 218 219 /* Move all data from old to new */ 220 fd_list_move_end( &new->list, &q->list ); 221 if (q->count && (!new->count)) { 222 CHECK_POSIX( pthread_cond_signal(&new->cond) ); 223 } 224 new->count += q->count; 225 226 /* Destroy old */ 227 CHECK_POSIX( pthread_mutex_unlock( &q->mtx ) ); 228 CHECK_POSIX( pthread_cond_destroy( &q->cond ) ); 229 CHECK_POSIX( pthread_mutex_destroy( &q->mtx ) ); 230 free(q); 231 232 /* Unlock new, we're done */ 233 CHECK_POSIX( pthread_mutex_unlock( &new->mtx ) ); 181 234 182 235 return 0; -
libfreeDiameter/lists.c
r14 r25 70 70 ASSERT(ref->head != item); 71 71 list_insert_after(ref, item); 72 } 73 74 /* Move all elements of list senti at the end of list ref */ 75 void fd_list_move_end(struct fd_list * ref, struct fd_list * senti) 76 { 77 ASSERT(ref->head == ref); 78 ASSERT(senti->head == senti); 79 80 if (senti->next == senti) 81 return; 82 83 senti->next->prev = ref->prev; 84 ref->prev->next = senti->next; 85 senti->prev->next = ref; 86 ref->prev = senti->prev; 87 senti->prev = senti; 88 senti->next = senti; 89 72 90 } 73 91
Note: See TracChangeset
for help on using the changeset viewer.