Changeset 1186:56c36d1007b4 in freeDiameter for libfdcore/cnxctx.c
- Timestamp:
- Jun 7, 2013, 7:48:34 PM (11 years ago)
- Branch:
- default
- Phase:
- public
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libfdcore/cnxctx.c
r1181 r1186 39 39 #include <net/if.h> 40 40 #include <ifaddrs.h> /* for getifaddrs */ 41 #include <sys/uio.h> /* writev */ 41 42 42 43 /* The maximum size of Diameter message we accept to receive (<= 2^24) to avoid too big mallocs in case of trashed headers */ … … 479 480 } 480 481 482 /* Mark the connection to tell if OOO delivery is permitted (only for SCTP) */ 483 int fd_cnx_unordered_delivery(struct cnxctx * conn, int is_allowed) 484 { 485 CHECK_PARAMS( conn ); 486 conn->cc_sctp_para.unordered = is_allowed; 487 return 0; 488 } 489 481 490 /* Return true if the connection supports unordered delivery of messages */ 482 int fd_cnx_is Multichan(struct cnxctx * conn)491 int fd_cnx_is_unordered_delivery_supported(struct cnxctx * conn) 483 492 { 484 493 CHECK_PARAMS_DO( conn, return 0 ); 485 494 #ifndef DISABLE_SCTP 486 495 if (conn->cc_proto == IPPROTO_SCTP) 487 return (conn->cc_sctp_para.str_ in > 1) || (conn->cc_sctp_para.str_out > 1);496 return (conn->cc_sctp_para.str_out > 1); 488 497 #endif /* DISABLE_SCTP */ 489 498 return 0; … … 531 540 } 532 541 542 static int fd_cnx_may_dtls(struct cnxctx * conn); 543 544 /* Get a short string representing the connection */ 545 int fd_cnx_proto_info(struct cnxctx * conn, char * buf, size_t len) 546 { 547 CHECK_PARAMS( conn ); 548 549 if (fd_cnx_teststate(conn, CC_STATUS_TLS)) { 550 snprintf(buf, len, "%s,%s,soc#%d", IPPROTO_NAME(conn->cc_proto), fd_cnx_may_dtls(conn) ? "DTLS" : "TLS", conn->cc_socket); 551 } else { 552 snprintf(buf, len, "%s,soc#%d", IPPROTO_NAME(conn->cc_proto), conn->cc_socket); 553 } 554 555 return 0; 556 } 557 533 558 /* Retrieve a list of all IP addresses of the local system from the kernel, using getifaddrs */ 534 559 int fd_cnx_get_local_eps(struct fd_list * list) … … 600 625 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)), /* Also timeout for sending, to avoid waiting forever */ ); 601 626 } 627 628 629 #ifdef GNUTLS_VERSION_300 630 /* The pull_timeout function for gnutls */ 631 static int fd_cnx_s_select (struct cnxctx * conn, unsigned int ms) 632 { 633 fd_set rfds; 634 struct timeval tv; 635 636 FD_ZERO (&rfds); 637 FD_SET (conn->cc_socket, &rfds); 638 639 tv.tv_sec = ms / 1000; 640 tv.tv_usec = (ms * 1000) % 1000000; 641 642 return select (conn->cc_socket + 1, &rfds, NULL, NULL, &tv); 643 } 644 #endif /* GNUTLS_VERSION_300 */ 602 645 603 646 /* 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 */ … … 628 671 } 629 672 630 /* Send */ 631 static ssize_t fd_cnx_s_send(struct cnxctx * conn, void *buffer, size_t length) 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) 632 676 { 633 677 ssize_t ret = 0; … … 635 679 again: 636 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 */ 702 static ssize_t fd_cnx_s_sendv(struct cnxctx * conn, const struct iovec * iov, int iovcnt) 703 { 704 ssize_t ret = 0; 705 int timedout = 0; 706 again: 707 ret = writev(conn->cc_socket, iov, iovcnt); 637 708 /* Handle special case of timeout */ 638 709 if ((ret < 0) && ((errno == EAGAIN) || (errno == EINTR))) { … … 1605 1676 /* Set the push and pull callbacks */ 1606 1677 if (!dtls) { 1678 #ifdef GNUTLS_VERSION_300 1679 GNUTLS_TRACE( gnutls_transport_set_pull_timeout_function( conn->cc_tls_para.session, (void *)fd_cnx_s_select ) ); 1680 #endif /* GNUTLS_VERSION_300 */ 1607 1681 GNUTLS_TRACE( gnutls_transport_set_pull_function(conn->cc_tls_para.session, (void *)fd_cnx_s_recv) ); 1682 #ifndef GNUTLS_VERSION_212 1608 1683 GNUTLS_TRACE( gnutls_transport_set_push_function(conn->cc_tls_para.session, (void *)fd_cnx_s_send) ); 1684 #else /* GNUTLS_VERSION_212 */ 1685 GNUTLS_TRACE( gnutls_transport_set_vec_push_function(conn->cc_tls_para.session, (void *)fd_cnx_s_sendv) ); 1686 #endif /* GNUTLS_VERSION_212 */ 1609 1687 } else { 1610 1688 TODO("DTLS push/pull functions"); … … 1784 1862 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_tls_para.session, buf + sent, len - sent), ); 1785 1863 } else { 1786 /* Maybe better to replace this call with sendmsg for atomic sending? */ 1787 CHECK_SYS_DO( ret = fd_cnx_s_send(conn, buf + sent, len - sent), ); 1864 struct iovec iov; 1865 iov.iov_base = buf + sent; 1866 iov.iov_len = len - sent; 1867 CHECK_SYS_DO( ret = fd_cnx_s_sendv(conn, &iov, 1), ); 1788 1868 } 1789 1869 if (ret <= 0) … … 1796 1876 1797 1877 /* Send a message -- this is synchronous -- and we assume it's never called by several threads at the same time (on the same conn), so we don't protect. */ 1798 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len , uint32_t flags)1799 { 1800 TRACE_ENTRY("%p %p %zd %x", conn, buf, len, flags);1878 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len) 1879 { 1880 TRACE_ENTRY("%p %p %zd", conn, buf, len); 1801 1881 1802 1882 CHECK_PARAMS(conn && (conn->cc_socket > 0) && (! fd_cnx_teststate(conn, CC_STATUS_ERROR)) && buf && len); … … 1812 1892 case IPPROTO_SCTP: { 1813 1893 int dtls = fd_cnx_uses_dtls(conn); 1814 1815 1894 if (!dtls) { 1816 if (flags & FD_CNX_ORDERED) { 1817 /* We send over stream #0 */ 1895 int stream = 0; 1896 if (conn->cc_sctp_para.unordered) { 1897 int limit; 1898 if (fd_cnx_teststate(conn, CC_STATUS_TLS)) 1899 limit = conn->cc_sctp_para.pairs; 1900 else 1901 limit = conn->cc_sctp_para.str_out; 1902 1903 if (limit > 1) { 1904 conn->cc_sctp_para.next += 1; 1905 conn->cc_sctp_para.next %= limit; 1906 stream = conn->cc_sctp_para.next; 1907 } 1908 } 1909 1910 if (stream == 0) { 1911 /* We can use default function, it sends over stream #0 */ 1818 1912 CHECK_FCT( send_simple(conn, buf, len) ); 1819 1913 } else { 1820 /* Default case : no flag specified */ 1821 1822 int another_str = 0; /* do we send over stream #0 ? */ 1823 1824 if ((conn->cc_sctp_para.str_out > 1) && ((!fd_cnx_teststate(conn, CC_STATUS_TLS)) || (conn->cc_sctp_para.pairs > 1))) { 1825 /* Update the id of the stream we will send this message over */ 1826 conn->cc_sctp_para.next += 1; 1827 conn->cc_sctp_para.next %= (fd_cnx_teststate(conn, CC_STATUS_TLS) ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out); 1828 another_str = (conn->cc_sctp_para.next ? 1 : 0); 1829 } 1830 1831 if ( ! another_str ) { 1832 CHECK_FCT( send_simple(conn, buf, len) ); 1914 if (!fd_cnx_teststate(conn, CC_STATUS_TLS)) { 1915 struct iovec iov; 1916 iov.iov_base = buf; 1917 iov.iov_len = len; 1918 1919 CHECK_SYS_DO( fd_sctp_sendstrv(conn, stream, &iov, 1), { fd_cnx_markerror(conn); return ENOTCONN; } ); 1833 1920 } else { 1834 if (!fd_cnx_teststate(conn, CC_STATUS_TLS)) { 1835 CHECK_FCT_DO( fd_sctp_sendstr(conn, conn->cc_sctp_para.next, buf, len), { fd_cnx_markerror(conn); return ENOTCONN; } ); 1836 } else { 1837 /* push the record to the appropriate session */ 1838 ssize_t ret; 1839 size_t sent = 0; 1840 ASSERT(conn->cc_sctp3436_data.array != NULL); 1841 do { 1842 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_sctp3436_data.array[conn->cc_sctp_para.next].session, buf + sent, len - sent), ); 1843 if (ret <= 0) 1844 return ENOTCONN; 1845 1846 sent += ret; 1847 } while ( sent < len ); 1848 } 1921 /* push the data to the appropriate session */ 1922 ssize_t ret; 1923 size_t sent = 0; 1924 ASSERT(conn->cc_sctp3436_data.array != NULL); 1925 do { 1926 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_sctp3436_data.array[stream].session, buf + sent, len - sent), ); 1927 if (ret <= 0) 1928 return ENOTCONN; 1929 1930 sent += ret; 1931 } while ( sent < len ); 1849 1932 } 1850 1933 } 1851 1934 } else { 1852 1935 /* DTLS */ 1853 /* We signal the push function directly to tell if using stream 0 or round-robin */ 1854 TODO("DTLS send"); 1855 return ENOTSUP; 1936 /* Multistream is handled at lower layer in the push/pull function */ 1937 CHECK_FCT( send_simple(conn, buf, len) ); 1856 1938 } 1857 1939 }
Note: See TracChangeset
for help on using the changeset viewer.