Changeset 209:b9f48f2f2a22 in freeDiameter
- Timestamp:
- Feb 16, 2010, 3:29:55 PM (14 years ago)
- Branch:
- default
- Phase:
- public
- Location:
- freeDiameter
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
freeDiameter/cnxctx.c
r208 r209 136 136 if (rc) 137 137 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); 138 snprintf(cnx->cc_id, sizeof(cnx->cc_id), " Srv TCP[%s]:%hu (%d)", addrbuf, port, cnx->cc_socket);138 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "TCP srv [%s]:%hu (%d)", addrbuf, port, cnx->cc_socket); 139 139 } 140 140 … … 171 171 172 172 /* Generate the name for the connection object */ 173 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "S rv SCTP:%hu (%d)", port, cnx->cc_socket);173 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "SCTP srv :%hu (%d)", port, cnx->cc_socket); 174 174 175 175 cnx->cc_proto = IPPROTO_SCTP; … … 218 218 CHECK_PARAMS_DO(serv, return NULL); 219 219 220 /* Accept the new connection -- this is blocking until new client enters or cancellation */220 /* Accept the new connection -- this is blocking until new client enters or until cancellation */ 221 221 CHECK_SYS_DO( cli_sock = accept(serv->cc_socket, (sSA *)&ss, &ss_len), return NULL ); 222 222 … … 247 247 } 248 248 249 snprintf(cli->cc_id, sizeof(cli->cc_id), "Incoming %s [%s]:%s (%d) @ serv (%d)", 250 IPPROTO_NAME(cli->cc_proto), 251 addrbuf, portbuf, 252 cli->cc_socket, serv->cc_socket); 249 snprintf(cli->cc_id, sizeof(cli->cc_id), "{%s} (%d) <- [%s]:%s (%d)", 250 IPPROTO_NAME(cli->cc_proto), serv->cc_socket, 251 addrbuf, portbuf, cli->cc_socket); 253 252 254 253 /* Name for log messages */ … … 316 315 } 317 316 318 snprintf(cnx->cc_id, sizeof(cnx->cc_id), " Client of TCP server[%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);317 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "{TCP} -> [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket); 319 318 320 319 /* Name for log messages */ … … 379 378 } 380 379 381 snprintf(cnx->cc_id, sizeof(cnx->cc_id), " Client of SCTP server[%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);380 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "{SCTP} -> [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket); 382 381 383 382 /* Name for log messages */ … … 420 419 { 421 420 CHECK_PARAMS_DO( conn, return 0 ); 422 return conn->cc_ tls;421 return conn->cc_status & CC_STATUS_TLS; 423 422 } 424 423 … … 494 493 /**************************************/ 495 494 495 /* An error occurred on the socket */ 496 void fd_cnx_markerror(struct cnxctx * conn) 497 { 498 TRACE_ENTRY("%p", conn); 499 CHECK_PARAMS_DO( conn, goto fatal ); 500 501 /* Mark the error */ 502 conn->cc_status |= CC_STATUS_ERROR; 503 504 /* Report the error if not reported yet, and not closing */ 505 if ((!(conn->cc_status & CC_STATUS_CLOSING )) && (!(conn->cc_status & CC_STATUS_SIGNALED ))) { 506 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), goto fatal); 507 conn->cc_status |= CC_STATUS_SIGNALED; 508 } 509 510 return; 511 fatal: 512 /* An unrecoverable error occurred, stop the daemon */ 513 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 514 } 515 496 516 /* Set the timeout option on the socket */ 497 517 void fd_cnx_s_setto(int sock) … … 504 524 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)), /* best effort only */ ); 505 525 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)), /* Also timeout for sending, to avoid waiting forever */ ); 506 } 507 508 /* A recv-like function, taking a cnxctx object instead of socket as entry. Only used to filter timeouts error (GNUTLS does not like these...)*/526 } 527 528 /* A recv-like function, taking a cnxctx object instead of socket as entry. We use it to quickly react to timeouts without traversing GNUTLS wrapper each time */ 509 529 ssize_t fd_cnx_s_recv(struct cnxctx * conn, void *buffer, size_t length) 510 530 { … … 515 535 /* Handle special case of timeout */ 516 536 if ((ret < 0) && (errno == EAGAIN)) { 517 if (! conn->cc_closing)537 if (! (conn->cc_status & CC_STATUS_CLOSING)) 518 538 goto again; /* don't care, just ignore */ 519 539 if (!timedout) { … … 521 541 goto again; 522 542 } 523 CHECK_SYS_DO(ret, /* continue */); 524 } 543 } 544 545 CHECK_SYS_DO(ret, /* continue */); 525 546 526 547 /* Mark the error */ 527 548 if (ret <= 0) 528 conn->cc_goterror=1;549 fd_cnx_markerror(conn); 529 550 530 551 return ret; … … 540 561 /* Handle special case of timeout */ 541 562 if ((ret < 0) && (errno == EAGAIN)) { 542 if (! conn->cc_closing)563 if (! (conn->cc_status & CC_STATUS_CLOSING)) 543 564 goto again; /* don't care, just ignore */ 544 565 if (!timedout) { … … 551 572 /* Mark the error */ 552 573 if (ret <= 0) 553 conn->cc_goterror=1;574 fd_cnx_markerror(conn); 554 575 555 576 return ret; … … 572 593 573 594 ASSERT( conn->cc_proto == IPPROTO_TCP ); 574 ASSERT( conn->cc_tls == 0);595 ASSERT( ! (conn->cc_status & CC_STATUS_TLS) ); 575 596 ASSERT( Target_Queue(conn) ); 576 597 … … 586 607 ret = fd_cnx_s_recv(conn, &header[received], sizeof(header) - received); 587 608 if (ret <= 0) { 588 CHECK_SYS_DO(ret, /* continue */); 589 goto error; /* Stop the thread, the recipient of the event will cleanup */ 609 goto out; /* Stop the thread, the event was already sent */ 590 610 } 591 611 … … 600 620 /* The message is suspect */ 601 621 TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %zd], assume disconnection", (int)header[0], length); 602 goto error; /* Stop the thread, the recipient of the event will cleanup */ 622 fd_cnx_markerror(conn); 623 goto out; /* Stop the thread, the recipient of the event will cleanup */ 603 624 } 604 625 605 626 /* Ok, now we can really receive the data */ 606 CHECK_MALLOC_DO( newmsg = malloc( length ), goto error);627 CHECK_MALLOC_DO( newmsg = malloc( length ), goto fatal ); 607 628 memcpy(newmsg, header, sizeof(header)); 608 629 … … 613 634 614 635 if (ret <= 0) { 615 CHECK_SYS_DO(ret, /* continue */);616 636 free(newmsg); 617 goto error; /* Stop the thread, the recipient of the event will cleanup */637 goto out; 618 638 } 619 639 received += ret; 620 640 } 621 641 622 /* We have received a complete message, send it*/642 /* We have received a complete message, pass it to the daemon */ 623 643 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */); 624 644 … … 628 648 TRACE_DEBUG(FULL, "Thread terminated"); 629 649 return NULL; 630 error: 631 if (!conn->cc_closing) { 632 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);633 }650 651 fatal: 652 /* An unrecoverable error occurred, stop the daemon */ 653 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 634 654 goto out; 635 655 } … … 645 665 646 666 TRACE_ENTRY("%p", arg); 647 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out);667 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto fatal); 648 668 649 669 /* Set the thread name */ … … 655 675 656 676 ASSERT( conn->cc_proto == IPPROTO_SCTP ); 657 ASSERT( conn->cc_tls == 0);677 ASSERT( ! (conn->cc_status & CC_STATUS_TLS) ); 658 678 ASSERT( Target_Queue(conn) ); 659 679 660 680 do { 661 CHECK_FCT_DO( fd_sctp_recvmeta(conn->cc_socket, NULL, &buf, &bufsz, &event, &conn->cc_ closing), goto error);681 CHECK_FCT_DO( fd_sctp_recvmeta(conn->cc_socket, NULL, &buf, &bufsz, &event, &conn->cc_status), goto fatal ); 662 682 if (event == FDEVP_CNX_ERROR) { 663 conn->cc_goterror = 1;664 goto error;665 } 666 667 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), event, bufsz, buf), goto error);683 fd_cnx_markerror(conn); 684 goto out; 685 } 686 687 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), event, bufsz, buf), goto fatal ); 668 688 669 689 } while (conn->cc_loop); … … 672 692 TRACE_DEBUG(FULL, "Thread terminated"); 673 693 return NULL; 674 error: 675 if (!conn->cc_closing) { 676 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);677 }694 695 fatal: 696 /* An unrecoverable error occurred, stop the daemon */ 697 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 678 698 goto out; 679 699 } 680 700 #endif /* DISABLE_SCTP */ 681 682 /* Returns 0 on error, received data size otherwise (always >= 0) */683 static ssize_t fd_tls_recv_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)684 {685 ssize_t ret;686 again:687 CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz),688 {689 switch (ret) {690 case GNUTLS_E_REHANDSHAKE:691 if (!conn->cc_closing)692 CHECK_GNUTLS_DO( ret = gnutls_handshake(session),693 {694 if (TRACE_BOOL(INFO)) {695 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));696 }697 ret = 0;698 goto end;699 } );700 701 case GNUTLS_E_AGAIN:702 case GNUTLS_E_INTERRUPTED:703 if (!conn->cc_closing)704 goto again;705 TRACE_DEBUG(INFO, "Connection is closing, so abord gnutls_record_recv now.");706 ret = 0;707 break;708 709 default:710 TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error");711 ret = 0;712 }713 } );714 end:715 if (ret <= 0)716 conn->cc_goterror = 1;717 return ret;718 }719 720 /* Wrapper around gnutls_record_send to handle some error codes */721 static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)722 {723 ssize_t ret;724 again:725 CHECK_GNUTLS_DO( ret = gnutls_record_send(session, data, sz),726 {727 switch (ret) {728 case GNUTLS_E_REHANDSHAKE:729 if (!conn->cc_closing)730 CHECK_GNUTLS_DO( ret = gnutls_handshake(session),731 {732 if (TRACE_BOOL(INFO)) {733 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));734 }735 goto end;736 } );737 738 case GNUTLS_E_AGAIN:739 case GNUTLS_E_INTERRUPTED:740 if (!conn->cc_closing)741 goto again;742 TRACE_DEBUG(INFO, "Connection is closing, so abord gnutls_record_send now.");743 break;744 745 default:746 TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error");747 }748 } );749 end:750 if (ret <= 0)751 conn->cc_goterror = 1;752 return ret;753 }754 755 756 /* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */757 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session)758 {759 /* No guarantee that GnuTLS preserves the message boundaries, so we re-build it as in TCP */760 do {761 uint8_t header[4];762 uint8_t * newmsg;763 size_t length;764 ssize_t ret = 0;765 size_t received = 0;766 767 do {768 ret = fd_tls_recv_handle_error(conn, session, &header[received], sizeof(header) - received);769 if (ret == 0) {770 /* The connection is closed */771 goto out;772 }773 received += ret;774 } while (received < sizeof(header));775 776 length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3];777 778 /* Check the received word is a valid beginning of a Diameter message */779 if ((header[0] != DIAMETER_VERSION) /* defined in <libfreeDiameter.h> */780 || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */781 /* The message is suspect */782 TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %zd], assume disconnection", (int)header[0], length);783 goto out;784 }785 786 /* Ok, now we can really receive the data */787 CHECK_MALLOC( newmsg = malloc( length ) );788 memcpy(newmsg, header, sizeof(header));789 790 while (received < length) {791 pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */792 ret = fd_tls_recv_handle_error(conn, session, newmsg + received, length - received);793 pthread_cleanup_pop(0);794 795 if (ret == 0) {796 free(newmsg);797 goto out; /* Stop the thread, the recipient of the event will cleanup */798 }799 received += ret;800 }801 802 /* We have received a complete message, send it */803 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */);804 805 } while (1);806 out:807 return ENOTCONN;808 }809 810 /* Receiver thread (TLS & 1 stream SCTP or TCP) : gnutls directly handles the socket, save records into the target queue */811 static void * rcvthr_tls_single(void * arg)812 {813 struct cnxctx * conn = arg;814 815 TRACE_ENTRY("%p", arg);816 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto error);817 818 /* Set the thread name */819 {820 char buf[48];821 snprintf(buf, sizeof(buf), "Receiver (%d) TLS/single stream", conn->cc_socket);822 fd_log_threadname ( buf );823 }824 825 ASSERT( conn->cc_tls == 1 );826 ASSERT( Target_Queue(conn) );827 828 CHECK_FCT_DO(fd_tls_rcvthr_core(conn, conn->cc_tls_para.session), /* continue */);829 error:830 if (!conn->cc_closing) {831 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);832 }833 TRACE_DEBUG(FULL, "Thread terminated");834 return NULL;835 }836 701 837 702 /* Start receving messages in clear (no TLS) on the connection */ … … 840 705 TRACE_ENTRY("%p %i", conn, loop); 841 706 842 CHECK_PARAMS( conn && Target_Queue(conn) && (! conn->cc_tls) && (!conn->cc_loop));707 CHECK_PARAMS( conn && Target_Queue(conn) && (!(conn->cc_status & CC_STATUS_TLS)) && (!conn->cc_loop)); 843 708 844 709 /* Release resources in case of a previous call was already made */ … … 861 726 default: 862 727 TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto); 728 ASSERT(0); 863 729 return ENOTSUP; 864 730 } … … 867 733 } 868 734 735 736 737 738 /* Returns 0 on error, received data size otherwise (always >= 0) */ 739 static ssize_t fd_tls_recv_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz) 740 { 741 ssize_t ret; 742 again: 743 CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz), 744 { 745 switch (ret) { 746 case GNUTLS_E_REHANDSHAKE: 747 if (!(conn->cc_status & CC_STATUS_CLOSING)) 748 CHECK_GNUTLS_DO( ret = gnutls_handshake(session), 749 { 750 if (TRACE_BOOL(INFO)) { 751 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); 752 } 753 goto end; 754 } ); 755 756 case GNUTLS_E_AGAIN: 757 case GNUTLS_E_INTERRUPTED: 758 if (!(conn->cc_status & CC_STATUS_CLOSING)) 759 goto again; 760 TRACE_DEBUG(INFO, "Connection is closing, so abord gnutls_record_recv now."); 761 break; 762 763 default: 764 TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error"); 765 } 766 } ); 767 end: 768 if (ret <= 0) 769 fd_cnx_markerror(conn); 770 return ret; 771 } 772 773 /* Wrapper around gnutls_record_send to handle some error codes */ 774 static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz) 775 { 776 ssize_t ret; 777 again: 778 CHECK_GNUTLS_DO( ret = gnutls_record_send(session, data, sz), 779 { 780 switch (ret) { 781 case GNUTLS_E_REHANDSHAKE: 782 if (!(conn->cc_status & CC_STATUS_CLOSING)) 783 CHECK_GNUTLS_DO( ret = gnutls_handshake(session), 784 { 785 if (TRACE_BOOL(INFO)) { 786 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); 787 } 788 goto end; 789 } ); 790 791 case GNUTLS_E_AGAIN: 792 case GNUTLS_E_INTERRUPTED: 793 if (!(conn->cc_status & CC_STATUS_CLOSING)) 794 goto again; 795 TRACE_DEBUG(INFO, "Connection is closing, so abord gnutls_record_send now."); 796 break; 797 798 default: 799 TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error"); 800 } 801 } ); 802 end: 803 if (ret <= 0) 804 fd_cnx_markerror(conn); 805 806 return ret; 807 } 808 809 810 /* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */ 811 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session) 812 { 813 /* No guarantee that GnuTLS preserves the message boundaries, so we re-build it as in TCP */ 814 do { 815 uint8_t header[4]; 816 uint8_t * newmsg; 817 size_t length; 818 ssize_t ret = 0; 819 size_t received = 0; 820 821 do { 822 ret = fd_tls_recv_handle_error(conn, session, &header[received], sizeof(header) - received); 823 if (ret <= 0) { 824 /* The connection is closed */ 825 goto out; 826 } 827 received += ret; 828 } while (received < sizeof(header)); 829 830 length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3]; 831 832 /* Check the received word is a valid beginning of a Diameter message */ 833 if ((header[0] != DIAMETER_VERSION) /* defined in <libfreeDiameter.h> */ 834 || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */ 835 /* The message is suspect */ 836 TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %zd], assume disconnection", (int)header[0], length); 837 fd_cnx_markerror(conn); 838 goto out; 839 } 840 841 /* Ok, now we can really receive the data */ 842 CHECK_MALLOC( newmsg = malloc( length ) ); 843 memcpy(newmsg, header, sizeof(header)); 844 845 while (received < length) { 846 pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */ 847 ret = fd_tls_recv_handle_error(conn, session, newmsg + received, length - received); 848 pthread_cleanup_pop(0); 849 850 if (ret <= 0) { 851 free(newmsg); 852 goto out; 853 } 854 received += ret; 855 } 856 857 /* We have received a complete message, pass it to the daemon */ 858 CHECK_FCT_DO( ret = fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), 859 { 860 free(newmsg); 861 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 862 return ret; 863 } ); 864 865 } while (1); 866 867 out: 868 return ENOTCONN; 869 } 870 871 /* Receiver thread (TLS & 1 stream SCTP or TCP) */ 872 static void * rcvthr_tls_single(void * arg) 873 { 874 struct cnxctx * conn = arg; 875 876 TRACE_ENTRY("%p", arg); 877 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), return NULL ); 878 879 /* Set the thread name */ 880 { 881 char buf[48]; 882 snprintf(buf, sizeof(buf), "Receiver (%d) TLS/single stream", conn->cc_socket); 883 fd_log_threadname ( buf ); 884 } 885 886 ASSERT( conn->cc_status & CC_STATUS_TLS ); 887 ASSERT( Target_Queue(conn) ); 888 889 /* The next function only returns when there is an error on the socket */ 890 CHECK_FCT_DO(fd_tls_rcvthr_core(conn, conn->cc_tls_para.session), /* continue */); 891 892 TRACE_DEBUG(FULL, "Thread terminated"); 893 return NULL; 894 } 895 869 896 /* Prepare a gnutls session object for handshake */ 870 897 int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority, void * alt_creds) 871 898 { 872 /* Create the mastersession context */899 /* Create the session context */ 873 900 CHECK_GNUTLS_DO( gnutls_init (session, mode), return ENOMEM ); 874 901 … … 901 928 gnutls_x509_crt_t cert; 902 929 time_t now; 930 931 TRACE_ENTRY("%p %d", conn, verbose); 932 CHECK_PARAMS(conn); 903 933 904 934 /* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */ … … 1107 1137 int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds) 1108 1138 { 1109 TRACE_ENTRY( "%p %d ", conn, mode);1110 CHECK_PARAMS( conn && (! conn->cc_tls) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) );1139 TRACE_ENTRY( "%p %d %p %p", conn, mode, priority, alt_creds); 1140 CHECK_PARAMS( conn && (!(conn->cc_status & CC_STATUS_TLS)) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) ); 1111 1141 1112 1142 /* Save the mode */ … … 1140 1170 } 1141 1171 1172 /* Mark the connection as protected from here, so that the gnutls credentials will be freed */ 1173 conn->cc_status |= CC_STATUS_TLS; 1174 1142 1175 /* Handshake master session */ 1143 1176 { … … 1148 1181 fd_log_debug("TLS Handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); 1149 1182 } 1150 conn->cc_goterror = 1;1183 fd_cnx_markerror(conn); 1151 1184 return EINVAL; 1152 1185 } ); … … 1155 1188 CHECK_FCT_DO( fd_tls_verify_credentials(conn->cc_tls_para.session, conn, 1), 1156 1189 { 1157 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_RDWR), /* Continue */);1158 gnutls_deinit(conn->cc_tls_para.session);1190 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_RDWR), ); 1191 fd_cnx_markerror(conn); 1159 1192 return EINVAL; 1160 1193 }); 1161 1194 } 1162 1163 /* Mark the connection as protected from here */1164 conn->cc_tls = 1;1165 1195 1166 1196 /* Multi-stream TLS: handshake other streams as well */ … … 1185 1215 { 1186 1216 TRACE_ENTRY("%p %p %p", conn, cert_list, cert_list_size); 1187 CHECK_PARAMS( conn && (conn->cc_ tls) && cert_list && cert_list_size );1217 CHECK_PARAMS( conn && (conn->cc_status & CC_STATUS_TLS) && cert_list && cert_list_size ); 1188 1218 1189 1219 /* This function only works for X.509 certificates. */ … … 1202 1232 1203 1233 /* 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. */ 1234 /* if the altfifo has been set on this conn object, this function must not be called */ 1204 1235 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len) 1205 1236 { … … 1264 1295 TRACE_ENTRY("%p %p %zd", conn, buf, len); 1265 1296 do { 1266 if (conn->cc_ tls) {1267 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_tls_para.session, buf + sent, len - sent), return ENOTCONN);1297 if (conn->cc_status & CC_STATUS_TLS) { 1298 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_tls_para.session, buf + sent, len - sent), ); 1268 1299 } else { 1269 CHECK_SYS( ret = fd_cnx_s_send(conn, buf + sent, len - sent) ); /* better to replace with sendmsg for atomic sending? */ 1270 } 1300 /* Maybe better to replace this call with sendmsg for atomic sending? */ 1301 CHECK_SYS_DO( ret = fd_cnx_s_send(conn, buf + sent, len - sent), ); 1302 } 1303 if (ret <= 0) 1304 return ENOTCONN; 1305 1271 1306 sent += ret; 1272 1307 } while ( sent < len ); … … 1279 1314 TRACE_ENTRY("%p %p %zd %i", conn, buf, len, ordered); 1280 1315 1281 CHECK_PARAMS(conn && (conn->cc_socket > 0) && (! conn->cc_goterror) && buf && len);1282 1283 TRACE_DEBUG(FULL, "Sending %zdb %sdata on connection %s", len, conn->cc_tls? "TLS-protected ":"", conn->cc_id);1316 CHECK_PARAMS(conn && (conn->cc_socket > 0) && (! (conn->cc_status & CC_STATUS_ERROR)) && buf && len); 1317 1318 TRACE_DEBUG(FULL, "Sending %zdb %sdata on connection %s", len, (conn->cc_status & CC_STATUS_TLS) ? "TLS-protected ":"", conn->cc_id); 1284 1319 1285 1320 switch (conn->cc_proto) { … … 1292 1327 int multistr = 0; 1293 1328 1294 if ((!ordered) && (conn->cc_sctp_para.str_out > 1) && ((! conn->cc_tls) || (conn->cc_sctp_para.pairs > 1))) {1329 if ((!ordered) && (conn->cc_sctp_para.str_out > 1) && ((! (conn->cc_status & CC_STATUS_TLS)) || (conn->cc_sctp_para.pairs > 1))) { 1295 1330 /* Update the id of the stream we will send this message on */ 1296 1331 conn->cc_sctp_para.next += 1; 1297 conn->cc_sctp_para.next %= ( conn->cc_tls? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out);1332 conn->cc_sctp_para.next %= ((conn->cc_status & CC_STATUS_TLS) ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out); 1298 1333 multistr = 1; 1299 1334 } … … 1302 1337 CHECK_FCT( send_simple(conn, buf, len) ); 1303 1338 } else { 1304 if (! conn->cc_tls) {1305 CHECK_FCT_DO( fd_sctp_sendstr(conn->cc_socket, conn->cc_sctp_para.next, buf, len, &conn->cc_ closing), { conn->cc_goterror = 1; return ENOTCONN; } );1339 if (!(conn->cc_status & CC_STATUS_TLS)) { 1340 CHECK_FCT_DO( fd_sctp_sendstr(conn->cc_socket, conn->cc_sctp_para.next, buf, len, &conn->cc_status), { fd_cnx_markerror(conn); return ENOTCONN; } ); 1306 1341 } else { 1307 1342 /* push the record to the appropriate session */ … … 1310 1345 ASSERT(conn->cc_sctps_data.array != NULL); 1311 1346 do { 1312 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_sctps_data.array[conn->cc_sctp_para.next].session, buf + sent, len - sent), return ENOTCONN ); 1347 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_sctps_data.array[conn->cc_sctp_para.next].session, buf + sent, len - sent), ); 1348 if (ret <= 0) 1349 return ENOTCONN; 1350 1313 1351 sent += ret; 1314 1352 } while ( sent < len ); … … 1321 1359 default: 1322 1360 TRACE_DEBUG(INFO, "Unknwon protocol: %d", conn->cc_proto); 1361 ASSERT(0); 1323 1362 return ENOTSUP; /* or EINVAL... */ 1324 1363 } … … 1339 1378 CHECK_PARAMS_DO(conn, return); 1340 1379 1341 conn->cc_ closing = 1;1380 conn->cc_status |= CC_STATUS_CLOSING; 1342 1381 1343 1382 /* Initiate shutdown of the TLS session(s): call gnutls_bye(WR), then read until error */ 1344 if (conn->cc_ tls) {1383 if (conn->cc_status & CC_STATUS_TLS) { 1345 1384 #ifndef DISABLE_SCTP 1346 1385 if (conn->cc_sctp_para.pairs > 1) { 1347 if (! conn->cc_goterror) {1386 if (! (conn->cc_status & CC_STATUS_ERROR )) { 1348 1387 /* Bye on master session */ 1349 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), /* Continue */ ); 1350 1388 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) ); 1389 } 1390 1391 if (! (conn->cc_status & CC_STATUS_ERROR ) ) { 1351 1392 /* and other stream pairs */ 1352 1393 fd_sctps_bye(conn); 1353 1394 } 1395 1396 if (! (conn->cc_status & CC_STATUS_ERROR ) ) { 1354 1397 /* Now wait for all decipher threads to terminate */ 1355 1398 fd_sctps_waitthreadsterm(conn); … … 1361 1404 /* Deinit gnutls resources */ 1362 1405 fd_sctps_gnutls_deinit_others(conn); 1363 gnutls_deinit(conn->cc_tls_para.session); 1406 if (conn->cc_tls_para.session) { 1407 gnutls_deinit(conn->cc_tls_para.session); 1408 conn->cc_tls_para.session = NULL; 1409 } 1364 1410 1365 1411 /* Destroy the wrapper (also stops the demux thread) */ … … 1369 1415 #endif /* DISABLE_SCTP */ 1370 1416 /* We are not using the sctps wrapper layer */ 1371 if (! conn->cc_goterror) {1417 if (! (conn->cc_status & CC_STATUS_ERROR ) ) { 1372 1418 /* Master session */ 1373 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), /* Continue */ ); 1374 1419 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) ); 1420 } 1421 1422 if (! (conn->cc_status & CC_STATUS_ERROR ) ) { 1375 1423 /* In this case, just wait for thread rcvthr_tls_single to terminate */ 1376 1424 if (conn->cc_rcvthr != (pthread_t)NULL) { … … 1384 1432 1385 1433 /* Free the resources of the TLS session */ 1386 gnutls_deinit(conn->cc_tls_para.session); 1434 if (conn->cc_tls_para.session) { 1435 gnutls_deinit(conn->cc_tls_para.session); 1436 conn->cc_tls_para.session = NULL; 1437 } 1387 1438 1388 1439 #ifndef DISABLE_SCTP -
freeDiameter/cnxctx.h
r203 r209 47 47 48 48 int cc_proto; /* IPPROTO_TCP or IPPROTO_SCTP */ 49 int cc_tls; /* Is TLS already started ? */ 50 int cc_goterror; /* True when an error occurred on the socket */ 51 int cc_closing; /* True if the object is being destroyed: we don't send events anymore */ 49 uint32_t cc_status; /* True if the object is being destroyed: we don't send events anymore */ 50 #define CC_STATUS_CLOSING 1 51 #define CC_STATUS_ERROR 2 52 #define CC_STATUS_SIGNALED 4 53 #define CC_STATUS_TLS 8 52 54 53 55 pthread_t cc_rcvthr; /* thread for receiving messages on the connection */ … … 79 81 } cc_sctps_data; 80 82 }; 83 84 void fd_cnx_markerror(struct cnxctx * conn); 81 85 82 86 /* Socket */ -
freeDiameter/sctp.c
r201 r209 1042 1042 1043 1043 /* Send a buffer over a specified stream */ 1044 int fd_sctp_sendstr(int sock, uint16_t strid, uint8_t * buf, size_t len, int * cc_ closing)1044 int fd_sctp_sendstr(int sock, uint16_t strid, uint8_t * buf, size_t len, int * cc_status) 1045 1045 { 1046 1046 struct msghdr mhdr; … … 1053 1053 int timedout = 0; 1054 1054 1055 TRACE_ENTRY("%d %hu %p %zd %p", sock, strid, buf, len, cc_ closing);1056 CHECK_PARAMS(cc_ closing);1055 TRACE_ENTRY("%d %hu %p %zd %p", sock, strid, buf, len, cc_status); 1056 CHECK_PARAMS(cc_status); 1057 1057 1058 1058 memset(&mhdr, 0, sizeof(mhdr)); … … 1084 1084 /* Handle special case of timeout */ 1085 1085 if ((ret < 0) && (errno == EAGAIN)) { 1086 if (! *cc_closing)1086 if (!(*cc_status & CC_STATUS_CLOSING)) 1087 1087 goto again; /* don't care, just ignore */ 1088 1088 if (!timedout) { … … 1099 1099 1100 1100 /* Receive the next data from the socket, or next notification */ 1101 int fd_sctp_recvmeta(int sock, uint16_t * strid, uint8_t ** buf, size_t * len, int *event, int * cc_ closing)1101 int fd_sctp_recvmeta(int sock, uint16_t * strid, uint8_t ** buf, size_t * len, int *event, int * cc_status) 1102 1102 { 1103 1103 ssize_t ret = 0; … … 1110 1110 int timedout = 0; 1111 1111 1112 TRACE_ENTRY("%d %p %p %p %p %p", sock, strid, buf, len, event, cc_ closing);1113 CHECK_PARAMS( (sock > 0) && buf && len && event && cc_ closing);1112 TRACE_ENTRY("%d %p %p %p %p %p", sock, strid, buf, len, event, cc_status); 1113 CHECK_PARAMS( (sock > 0) && buf && len && event && cc_status ); 1114 1114 1115 1115 /* Cleanup out parameters */ … … 1145 1145 /* First, handle timeouts (same as fd_cnx_s_recv) */ 1146 1146 if ((ret < 0) && (errno == EAGAIN)) { 1147 if (! *cc_closing)1147 if (!(*cc_status & CC_STATUS_CLOSING)) 1148 1148 goto again; /* don't care, just ignore */ 1149 1149 if (!timedout) { -
freeDiameter/sctps.c
r207 r209 87 87 88 88 do { 89 CHECK_FCT_DO( fd_sctp_recvmeta(conn->cc_socket, &strid, &buf, &bufsz, &event, &conn->cc_ closing), goto error);89 CHECK_FCT_DO( fd_sctp_recvmeta(conn->cc_socket, &strid, &buf, &bufsz, &event, &conn->cc_status), goto fatal ); 90 90 switch (event) { 91 91 case FDEVP_CNX_MSG_RECV: 92 /* Demux this message in the appropriate fifo, another thread will pull, gnutls process, and send intarget queue */92 /* Demux this message to the appropriate fifo, another thread will pull, gnutls process, and send to target queue */ 93 93 if (strid < conn->cc_sctp_para.pairs) { 94 CHECK_FCT_DO(fd_event_send(conn->cc_sctps_data.array[strid].raw_recv, event, bufsz, buf), goto error);94 CHECK_FCT_DO(fd_event_send(conn->cc_sctps_data.array[strid].raw_recv, event, bufsz, buf), goto fatal ); 95 95 } else { 96 96 TRACE_DEBUG(INFO, "Received packet (%d bytes) on out-of-range stream #%s from %s, discarded.", bufsz, strid, conn->cc_remid); … … 101 101 case FDEVP_CNX_EP_CHANGE: 102 102 /* Send this event to the target queue */ 103 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), event, bufsz, buf), goto error);103 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), event, bufsz, buf), goto fatal ); 104 104 break; 105 105 106 106 case FDEVP_CNX_ERROR: 107 fd_cnx_markerror(conn); 108 goto out; 109 107 110 default: 108 goto error;111 goto fatal; 109 112 } 110 113 … … 114 117 TRACE_DEBUG(FULL, "Thread terminated"); 115 118 return NULL; 116 error: 117 if (!conn->cc_closing) { 118 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */); 119 } 120 119 120 fatal: 121 /* An unrecoverable error occurred, stop the daemon */ 122 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 121 123 goto out; 122 124 } … … 140 142 } 141 143 144 /* The next function loops while there is no error */ 142 145 CHECK_FCT_DO(fd_tls_rcvthr_core(cnx, ctx->strid ? ctx->session : cnx->cc_tls_para.session), /* continue */); 143 146 error: 144 if (!cnx->cc_closing) { 145 CHECK_FCT_DO( fd_event_send( Target_Queue(cnx), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */); 146 } 147 fd_cnx_markerror(cnx); 147 148 TRACE_DEBUG(FULL, "Thread terminated"); 148 149 return NULL; … … 161 162 CHECK_PARAMS_DO( tr && data, { errno = EINVAL; return -1; } ); 162 163 163 CHECK_FCT_DO( fd_sctp_sendstr(ctx->parent->cc_socket, ctx->strid, (uint8_t *)data, len, &ctx->parent->cc_ closing), /* errno is already set */ return -1 );164 CHECK_FCT_DO( fd_sctp_sendstr(ctx->parent->cc_socket, ctx->strid, (uint8_t *)data, len, &ctx->parent->cc_status), /* errno is already set */ return -1 ); 164 165 165 166 return len; … … 176 177 CHECK_PARAMS_DO( tr && buf, { errno = EINVAL; return -1; } ); 177 178 178 /* If we don't have data available now, pull new message from the fifo -- this is blocking */179 /* If we don't have data available now, pull new message from the fifo -- this is blocking (until the queue is destroyed) */ 179 180 if (!ctx->partial.buf) { 180 181 int ev; … … 231 232 pthread_rwlock_t lock; 232 233 struct cnxctx *parent; 233 /* Add another list to chain in a global list to implement a garbage collector on sessions */234 /* Add another list to chain in a global list to implement a garbage collector on sessions -- TODO */ 234 235 }; 235 236 … … 336 337 /* Check the data is the same */ 337 338 if ((data.size != sr->data.size) || memcmp(data.data, sr->data.data, data.size)) { 338 TRACE_DEBUG( SR_LEVEL, "GnuTLS tried to store a session with same key and different data!");339 TRACE_DEBUG(INFO, "GnuTLS tried to store a session with same key and different data!"); 339 340 ret = -1; 340 341 } else { … … 571 572 } 572 573 573 return errors ? ENOTCONN : 0; 574 if (errors) { 575 TRACE_DEBUG(INFO, "Handshake failed on %d/%hd stream pairs", errors, conn->cc_sctp_para.pairs); 576 fd_cnx_markerror(conn); 577 return ENOTCONN; 578 } 579 580 return 0; 574 581 } 575 582 … … 599 606 /* End all TLS sessions, in series (not as efficient as paralel, but simpler) */ 600 607 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { 601 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_sctps_data.array[i].session, GNUTLS_SHUT_WR), /* Continue */ ); 608 if (!conn->cc_status & CC_STATUS_ERROR) { 609 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_sctps_data.array[i].session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) ); 610 } 602 611 } 603 612 } … … 629 638 630 639 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { 631 gnutls_deinit(conn->cc_sctps_data.array[i].session); 640 if (conn->cc_sctps_data.array[i].session) { 641 gnutls_deinit(conn->cc_sctps_data.array[i].session); 642 conn->cc_sctps_data.array[i].session = NULL; 643 } 632 644 } 633 645 } … … 666 678 fd_event_destroy( &conn->cc_sctps_data.array[i].raw_recv, free ); 667 679 free(conn->cc_sctps_data.array[i].partial.buf); 668 /* gnutls_session was already deinit */ 680 if (conn->cc_sctps_data.array[i].session) { 681 gnutls_deinit(conn->cc_sctps_data.array[i].session); 682 conn->cc_sctps_data.array[i].session = NULL; 683 } 669 684 } 670 685
Note: See TracChangeset
for help on using the changeset viewer.