comparison libfdcore/cnxctx.c @ 1214:76ac4bb75f0e

Merged with latest proposed version
author Sebastien Decugis <sdecugis@freediameter.net>
date Mon, 17 Jun 2013 10:11:57 +0800
parents e1ced4db7f67 98478a8aabb1
children 1e8267ad057c
comparison
equal deleted inserted replaced
1188:e1ced4db7f67 1214:76ac4bb75f0e
290 TRACE_ENTRY("%p %d", sa, addrlen); 290 TRACE_ENTRY("%p %d", sa, addrlen);
291 CHECK_PARAMS_DO( sa && addrlen, return NULL ); 291 CHECK_PARAMS_DO( sa && addrlen, return NULL );
292 292
293 fd_sa_sdump_numeric(sa_buf, sa); 293 fd_sa_sdump_numeric(sa_buf, sa);
294 294
295 LOG_D("Connecting to TCP %s...", sa_buf);
296
295 /* Create the socket and connect, which can take some time and/or fail */ 297 /* Create the socket and connect, which can take some time and/or fail */
296 { 298 {
297 int ret = fd_tcp_client( &sock, sa, addrlen ); 299 int ret = fd_tcp_client( &sock, sa, addrlen );
298 if (ret != 0) { 300 if (ret != 0) {
299 LOG_A("TCP connection to %s failed: %s", sa_buf, strerror(ret)); 301 LOG_D("TCP connection to %s failed: %s", sa_buf, strerror(ret));
300 return NULL; 302 return NULL;
301 } 303 }
302 } 304 }
303 305
304 /* Once the socket is created successfuly, prepare the remaining of the cnx */ 306 /* Once the socket is created successfuly, prepare the remaining of the cnx */
345 TRACE_ENTRY("%p", list); 347 TRACE_ENTRY("%p", list);
346 CHECK_PARAMS_DO( list && !FD_IS_LIST_EMPTY(list), return NULL ); 348 CHECK_PARAMS_DO( list && !FD_IS_LIST_EMPTY(list), return NULL );
347 349
348 fd_sa_sdump_numeric(sa_buf, &((struct fd_endpoint *)(list->next))->sa); 350 fd_sa_sdump_numeric(sa_buf, &((struct fd_endpoint *)(list->next))->sa);
349 351
352 LOG_D("Connecting to SCTP %s:%hu...", sa_buf, port);
353
350 { 354 {
351 int ret = fd_sctp_client( &sock, no_ip6, port, list ); 355 int ret = fd_sctp_client( &sock, no_ip6, port, list );
352 if (ret != 0) { 356 if (ret != 0) {
353 LOG_A("SCTP connection to [%s,...] failed: %s", sa_buf, strerror(ret)); 357 LOG_D("SCTP connection to [%s,...] failed: %s", sa_buf, strerror(ret));
354 return NULL; 358 return NULL;
355 } 359 }
356 } 360 }
357 361
358 /* Once the socket is created successfuly, prepare the remaining of the cnx */ 362 /* Once the socket is created successfuly, prepare the remaining of the cnx */
608 612
609 return; 613 return;
610 fatal: 614 fatal:
611 /* An unrecoverable error occurred, stop the daemon */ 615 /* An unrecoverable error occurred, stop the daemon */
612 ASSERT(0); 616 ASSERT(0);
613 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 617 CHECK_FCT_DO(fd_core_shutdown(), );
614 } 618 }
615 619
616 /* Set the timeout option on the socket */ 620 /* Set the timeout option on the socket */
617 void fd_cnx_s_setto(int sock) 621 void fd_cnx_s_setto(int sock)
618 { 622 {
619 struct timeval tv; 623 struct timeval tv;
620 624
621 /* Set a timeout on the socket so that in any case we are not stuck waiting for something */ 625 /* Set a timeout on the socket so that in any case we are not stuck waiting for something */
622 memset(&tv, 0, sizeof(tv)); 626 memset(&tv, 0, sizeof(tv));
623 tv.tv_sec = 3; /* allow 3 seconds timeout for TLS session cleanup */ 627 tv.tv_usec = 100000L; /* 100ms, to react quickly to head-of-the-line blocking. */
624 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)), /* best effort only */ ); 628 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)), );
625 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)), /* Also timeout for sending, to avoid waiting forever */ ); 629 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)), );
626 } 630 }
627 631
628 632
629 #ifdef GNUTLS_VERSION_300 633 #ifdef GNUTLS_VERSION_300
630 /* The pull_timeout function for gnutls */ 634 /* The pull_timeout function for gnutls */
668 } 672 }
669 673
670 return ret; 674 return ret;
671 } 675 }
672 676
673 /* Send, for older GNUTLS */
674 #ifndef GNUTLS_VERSION_212
675 static ssize_t fd_cnx_s_send(struct cnxctx * conn, const void *buffer, size_t length)
676 {
677 ssize_t ret = 0;
678 int timedout = 0;
679 again:
680 ret = send(conn->cc_socket, buffer, length, 0);
681 /* Handle special case of timeout */
682 if ((ret < 0) && ((errno == EAGAIN) || (errno == EINTR))) {
683 pthread_testcancel();
684 if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING ))
685 goto again; /* don't care, just ignore */
686 if (!timedout) {
687 timedout ++; /* allow for one timeout while closing */
688 goto again;
689 }
690 CHECK_SYS_DO(ret, /* continue */);
691 }
692
693 /* Mark the error */
694 if (ret <= 0)
695 fd_cnx_markerror(conn);
696
697 return ret;
698 }
699 #endif /* GNUTLS_VERSION_212 */
700
701 /* Send */ 677 /* Send */
702 static ssize_t fd_cnx_s_sendv(struct cnxctx * conn, const struct iovec * iov, int iovcnt) 678 static ssize_t fd_cnx_s_sendv(struct cnxctx * conn, const struct iovec * iov, int iovcnt)
703 { 679 {
704 ssize_t ret = 0; 680 ssize_t ret = 0;
705 int timedout = 0; 681 struct timespec ts, now;
682 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), return -1 );
706 again: 683 again:
707 ret = writev(conn->cc_socket, iov, iovcnt); 684 ret = writev(conn->cc_socket, iov, iovcnt);
708 /* Handle special case of timeout */ 685 /* Handle special case of timeout */
709 if ((ret < 0) && ((errno == EAGAIN) || (errno == EINTR))) { 686 if ((ret < 0) && ((errno == EAGAIN) || (errno == EINTR))) {
687 ret = -errno;
710 pthread_testcancel(); 688 pthread_testcancel();
711 if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING )) 689
690 /* Check how much time we were blocked for this sending. */
691 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), return -1 );
692 if ( ((now.tv_sec - ts.tv_sec) * 1000 + ((now.tv_nsec - ts.tv_nsec) / 1000000L)) > MAX_HOTL_BLOCKING_TIME) {
693 LOG_D("Unable to send any data for %dms, closing the connection", MAX_HOTL_BLOCKING_TIME);
694 } else if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING )) {
712 goto again; /* don't care, just ignore */ 695 goto again; /* don't care, just ignore */
713 if (!timedout) { 696 }
714 timedout ++; /* allow for one timeout while closing */ 697
715 goto again; 698 /* propagate the error */
716 } 699 errno = -ret;
700 ret = -1;
717 CHECK_SYS_DO(ret, /* continue */); 701 CHECK_SYS_DO(ret, /* continue */);
718 } 702 }
719 703
720 /* Mark the error */ 704 /* Mark the error */
721 if (ret <= 0) 705 if (ret <= 0)
722 fd_cnx_markerror(conn); 706 fd_cnx_markerror(conn);
723 707
724 return ret; 708 return ret;
725 } 709 }
710
711 /* Send, for older GNUTLS */
712 #ifndef GNUTLS_VERSION_212
713 static ssize_t fd_cnx_s_send(struct cnxctx * conn, const void *buffer, size_t length)
714 {
715 struct iovec iov;
716 iov.iov_base = (void *)buffer;
717 iov.iov_len = length;
718 return fd_cnx_s_sendv(conn, &iov, 1);
719 }
720 #endif /* GNUTLS_VERSION_212 */
726 721
727 #define ALIGNOF(t) ((char *)(&((struct { char c; t _h; } *)0)->_h) - (char *)0) /* Could use __alignof__(t) on some systems but this is more portable probably */ 722 #define ALIGNOF(t) ((char *)(&((struct { char c; t _h; } *)0)->_h) - (char *)0) /* Could use __alignof__(t) on some systems but this is more portable probably */
728 #define PMDL_PADDED(len) ( ((len) + ALIGNOF(struct fd_msg_pmdl) - 1) & ~(ALIGNOF(struct fd_msg_pmdl) - 1) ) 723 #define PMDL_PADDED(len) ( ((len) + ALIGNOF(struct fd_msg_pmdl) - 1) & ~(ALIGNOF(struct fd_msg_pmdl) - 1) )
729 724
730 size_t fd_msg_pmdl_sizewithoverhead(size_t datalen) 725 size_t fd_msg_pmdl_sizewithoverhead(size_t datalen)
805 if (ret <= 0) { 800 if (ret <= 0) {
806 goto out; /* Stop the thread, the event was already sent */ 801 goto out; /* Stop the thread, the event was already sent */
807 } 802 }
808 803
809 received += ret; 804 received += ret;
805
806 if (header[0] != DIAMETER_VERSION)
807 break; /* No need to wait for 4 bytes in this case */
810 } while (received < sizeof(header)); 808 } while (received < sizeof(header));
811 809
812 rcv_data.length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3]; 810 rcv_data.length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3];
813 811
814 /* Check the received word is a valid begining of a Diameter message */ 812 /* Check the received word is a valid begining of a Diameter message */
840 838
841 /* We have received a complete message, pass it to the daemon */ 839 /* We have received a complete message, pass it to the daemon */
842 CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, rcv_data.length, rcv_data.buffer), 840 CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, rcv_data.length, rcv_data.buffer),
843 { 841 {
844 free_rcvdata(&rcv_data); 842 free_rcvdata(&rcv_data);
845 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 843 goto fatal;
846 return NULL;
847 } ); 844 } );
848 845
849 } while (conn->cc_loop); 846 } while (conn->cc_loop);
850 847
851 out: 848 out:
852 TRACE_DEBUG(FULL, "Thread terminated"); 849 TRACE_DEBUG(FULL, "Thread terminated");
853 return NULL; 850 return NULL;
854 851
855 fatal: 852 fatal:
856 /* An unrecoverable error occurred, stop the daemon */ 853 /* An unrecoverable error occurred, stop the daemon */
857 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 854 CHECK_FCT_DO(fd_core_shutdown(), );
858 goto out; 855 goto out;
859 } 856 }
860 857
861 #ifndef DISABLE_SCTP 858 #ifndef DISABLE_SCTP
862 /* Receiver thread (SCTP & noTLS) : incoming message is directly saved into cc_incoming, no need to care for the stream ID */ 859 /* Receiver thread (SCTP & noTLS) : incoming message is directly saved into cc_incoming, no need to care for the stream ID */
905 TRACE_DEBUG(FULL, "Thread terminated"); 902 TRACE_DEBUG(FULL, "Thread terminated");
906 return NULL; 903 return NULL;
907 904
908 fatal: 905 fatal:
909 /* An unrecoverable error occurred, stop the daemon */ 906 /* An unrecoverable error occurred, stop the daemon */
910 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 907 CHECK_FCT_DO(fd_core_shutdown(), );
911 goto out; 908 goto out;
912 } 909 }
913 #endif /* DISABLE_SCTP */ 910 #endif /* DISABLE_SCTP */
914 911
915 /* Start receving messages in clear (no TLS) on the connection */ 912 /* Start receving messages in clear (no TLS) on the connection */
999 996
1000 /* Wrapper around gnutls_record_send to handle some error codes. This is also used for DTLS-protected associations */ 997 /* Wrapper around gnutls_record_send to handle some error codes. This is also used for DTLS-protected associations */
1001 static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz) 998 static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
1002 { 999 {
1003 ssize_t ret; 1000 ssize_t ret;
1001 struct timespec ts, now;
1002 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), return -1 );
1004 again: 1003 again:
1005 CHECK_GNUTLS_DO( ret = gnutls_record_send(session, data, sz), 1004 CHECK_GNUTLS_DO( ret = gnutls_record_send(session, data, sz),
1006 { 1005 {
1006 pthread_testcancel();
1007 switch (ret) { 1007 switch (ret) {
1008 case GNUTLS_E_REHANDSHAKE: 1008 case GNUTLS_E_REHANDSHAKE:
1009 if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING)) { 1009 if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING)) {
1010 CHECK_GNUTLS_DO( ret = gnutls_handshake(session), 1010 CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
1011 { 1011 {
1016 } ); 1016 } );
1017 } 1017 }
1018 1018
1019 case GNUTLS_E_AGAIN: 1019 case GNUTLS_E_AGAIN:
1020 case GNUTLS_E_INTERRUPTED: 1020 case GNUTLS_E_INTERRUPTED:
1021 if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING)) 1021 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), return -1 );
1022 if ( ((now.tv_sec - ts.tv_sec) * 1000 + ((now.tv_nsec - ts.tv_nsec) / 1000000L)) > MAX_HOTL_BLOCKING_TIME) {
1023 LOG_D("Unable to send any data for %dms, closing the connection", MAX_HOTL_BLOCKING_TIME);
1024 } else if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING )) {
1022 goto again; 1025 goto again;
1023 TRACE_DEBUG(INFO, "Connection is closing, so abord gnutls_record_send now."); 1026 }
1024 break; 1027 break;
1025 1028
1026 default: 1029 default:
1027 if (gnutls_error_is_fatal (ret) == 0) { 1030 if (gnutls_error_is_fatal (ret) == 0) {
1028 LOG_N("Ignoring non-fatal GNU TLS error: %s", gnutls_strerror (ret)); 1031 LOG_N("Ignoring non-fatal GNU TLS error: %s", gnutls_strerror (ret));
1096 1099
1097 /* We have received a complete message, pass it to the daemon */ 1100 /* We have received a complete message, pass it to the daemon */
1098 CHECK_FCT_DO( ret = fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, rcv_data.length, rcv_data.buffer), 1101 CHECK_FCT_DO( ret = fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, rcv_data.length, rcv_data.buffer),
1099 { 1102 {
1100 free_rcvdata(&rcv_data); 1103 free_rcvdata(&rcv_data);
1101 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 1104 CHECK_FCT_DO(fd_core_shutdown(), );
1102 return ret; 1105 return ret;
1103 } ); 1106 } );
1104 1107
1105 } while (1); 1108 } while (1);
1106 1109
1631 return 1; 1634 return 1;
1632 #endif /* DISABLE_SCTP */ 1635 #endif /* DISABLE_SCTP */
1633 return 0; 1636 return 0;
1634 } 1637 }
1635 1638
1639 #ifndef DISABLE_SCTP
1636 static int fd_cnx_uses_dtls(struct cnxctx * conn) { 1640 static int fd_cnx_uses_dtls(struct cnxctx * conn) {
1637 return fd_cnx_may_dtls(conn) && (fd_cnx_teststate(conn, CC_STATUS_TLS)); 1641 return fd_cnx_may_dtls(conn) && (fd_cnx_teststate(conn, CC_STATUS_TLS));
1638 } 1642 }
1643 #endif /* DISABLE_SCTP */
1639 1644
1640 /* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */ 1645 /* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */
1641 int fd_cnx_handshake(struct cnxctx * conn, int mode, int algo, char * priority, void * alt_creds) 1646 int fd_cnx_handshake(struct cnxctx * conn, int mode, int algo, char * priority, void * alt_creds)
1642 { 1647 {
1643 int dtls = 0; 1648 int dtls = 0;
"Welcome to our mercurial repository"