Navigation


Changeset 1186:56c36d1007b4 in freeDiameter for libfdcore/cnxctx.c


Ignore:
Timestamp:
Jun 7, 2013, 7:48:34 PM (11 years ago)
Author:
Sebastien Decugis <sdecugis@freediameter.net>
Branch:
default
Phase:
public
Message:

Further preparation of the DTLS integration. Some cleanups in the GNUTLS handling.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libfdcore/cnxctx.c

    r1181 r1186  
    3939#include <net/if.h>
    4040#include <ifaddrs.h> /* for getifaddrs */
     41#include <sys/uio.h> /* writev */
    4142
    4243/* The maximum size of Diameter message we accept to receive (<= 2^24) to avoid too big mallocs in case of trashed headers */
     
    479480}
    480481
     482/* Mark the connection to tell if OOO delivery is permitted (only for SCTP) */
     483int 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
    481490/* Return true if the connection supports unordered delivery of messages */
    482 int fd_cnx_isMultichan(struct cnxctx * conn)
     491int fd_cnx_is_unordered_delivery_supported(struct cnxctx * conn)
    483492{
    484493        CHECK_PARAMS_DO( conn, return 0 );
    485494        #ifndef DISABLE_SCTP
    486495        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);
    488497        #endif /* DISABLE_SCTP */
    489498        return 0;
     
    531540}
    532541
     542static int fd_cnx_may_dtls(struct cnxctx * conn);
     543
     544/* Get a short string representing the connection */
     545int 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
    533558/* Retrieve a list of all IP addresses of the local system from the kernel, using getifaddrs */
    534559int fd_cnx_get_local_eps(struct fd_list * list)
     
    600625        CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)), /* Also timeout for sending, to avoid waiting forever */ );
    601626}
     627
     628
     629#ifdef GNUTLS_VERSION_300
     630/* The pull_timeout function for gnutls */
     631static 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 */
    602645
    603646/* 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 */
     
    628671}
    629672
    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
     675static ssize_t fd_cnx_s_send(struct cnxctx * conn, const void *buffer, size_t length)
    632676{
    633677        ssize_t ret = 0;
     
    635679again:
    636680        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 */
     702static 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;
     706again:
     707        ret = writev(conn->cc_socket, iov, iovcnt);
    637708        /* Handle special case of timeout */
    638709        if ((ret < 0) && ((errno == EAGAIN) || (errno == EINTR))) {
     
    16051676                /* Set the push and pull callbacks */
    16061677                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 */
    16071681                        GNUTLS_TRACE( gnutls_transport_set_pull_function(conn->cc_tls_para.session, (void *)fd_cnx_s_recv) );
     1682                        #ifndef GNUTLS_VERSION_212
    16081683                        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 */
    16091687                } else {
    16101688                        TODO("DTLS push/pull functions");
     
    17841862                        CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_tls_para.session, buf + sent, len - sent),  );
    17851863                } 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), );
    17881868                }
    17891869                if (ret <= 0)
     
    17961876
    17971877/* 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);
     1878int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len)
     1879{
     1880        TRACE_ENTRY("%p %p %zd", conn, buf, len);
    18011881       
    18021882        CHECK_PARAMS(conn && (conn->cc_socket > 0) && (! fd_cnx_teststate(conn, CC_STATUS_ERROR)) && buf && len);
     
    18121892                case IPPROTO_SCTP: {
    18131893                        int dtls = fd_cnx_uses_dtls(conn);
    1814 
    18151894                        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 */
    18181912                                        CHECK_FCT( send_simple(conn, buf, len) );
    18191913                                } 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; } );
    18331920                                        } 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 );
    18491932                                        }
    18501933                                }
    18511934                        } else {
    18521935                                /* 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) );
    18561938                        }
    18571939                }
Note: See TracChangeset for help on using the changeset viewer.