Navigation


Changeset 1200:ce2b00dc86c1 in freeDiameter for libfdcore


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

React quickly to head-of-the-line blocking in case of network failure. Can be adapted with MAX_HOTL_BLOCKING_TIME constant in cnxctx.h

Location:
libfdcore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • libfdcore/cnxctx.c

    r1198 r1200  
    625625        /* Set a timeout on the socket so that in any case we are not stuck waiting for something */
    626626        memset(&tv, 0, sizeof(tv));
    627         tv.tv_sec = 3;  /* allow 3 seconds timeout for TLS session cleanup */
    628         CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)), /* best effort only */ );
    629         CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)), /* Also timeout for sending, to avoid waiting forever */ );
     627        tv.tv_usec = 100000L;   /* 100ms, to react quickly to head-of-the-line blocking. */
     628        CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)), );
     629        CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)), );
    630630}
    631631
     
    675675}
    676676
    677 /* Send, for older GNUTLS */
    678 #ifndef GNUTLS_VERSION_212
    679 static ssize_t fd_cnx_s_send(struct cnxctx * conn, const void *buffer, size_t length)
    680 {
    681         ssize_t ret = 0;
    682         int timedout = 0;
    683 again:
    684         ret = send(conn->cc_socket, buffer, length, 0);
    685         /* Handle special case of timeout */
    686         if ((ret < 0) && ((errno == EAGAIN) || (errno == EINTR))) {
    687                 pthread_testcancel();
    688                 if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING ))
    689                         goto again; /* don't care, just ignore */
    690                 if (!timedout) {
    691                         timedout ++; /* allow for one timeout while closing */
    692                         goto again;
    693                 }
    694                 CHECK_SYS_DO(ret, /* continue */);
    695         }
    696        
    697         /* Mark the error */
    698         if (ret <= 0)
    699                 fd_cnx_markerror(conn);
    700        
    701         return ret;
    702 }
    703 #endif /* GNUTLS_VERSION_212 */
    704 
    705677/* Send */
    706678static ssize_t fd_cnx_s_sendv(struct cnxctx * conn, const struct iovec * iov, int iovcnt)
    707679{
    708680        ssize_t ret = 0;
    709         int timedout = 0;
     681        struct timespec ts, now;
     682        CHECK_SYS_DO(  clock_gettime(CLOCK_REALTIME, &ts), return -1 );
    710683again:
    711684        ret = writev(conn->cc_socket, iov, iovcnt);
    712685        /* Handle special case of timeout */
    713686        if ((ret < 0) && ((errno == EAGAIN) || (errno == EINTR))) {
     687                ret = -errno;
    714688                pthread_testcancel();
    715                 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 )) {
    716695                        goto again; /* don't care, just ignore */
    717                 if (!timedout) {
    718                         timedout ++; /* allow for one timeout while closing */
    719                         goto again;
    720                 }
     696                }
     697               
     698                /* propagate the error */
     699                errno = -ret;
     700                ret = -1;
    721701                CHECK_SYS_DO(ret, /* continue */);
    722702        }
     
    728708        return ret;
    729709}
     710
     711/* Send, for older GNUTLS */
     712#ifndef GNUTLS_VERSION_212
     713static 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 */
    730721
    731722#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 */
     
    1008999{
    10091000        ssize_t ret;
     1001        struct timespec ts, now;
     1002        CHECK_SYS_DO(  clock_gettime(CLOCK_REALTIME, &ts), return -1 );
    10101003again: 
    10111004        CHECK_GNUTLS_DO( ret = gnutls_record_send(session, data, sz),
    10121005                {
     1006                        pthread_testcancel();
    10131007                        switch (ret) {
    10141008                                case GNUTLS_E_REHANDSHAKE:
     
    10251019                                case GNUTLS_E_AGAIN:
    10261020                                case GNUTLS_E_INTERRUPTED:
    1027                                         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 )) {
    10281025                                                goto again;
    1029                                         TRACE_DEBUG(INFO, "Connection is closing, so abord gnutls_record_send now.");
     1026                                        }
    10301027                                        break;
    10311028
  • libfdcore/cnxctx.h

    r1186 r1200  
    3838#ifndef _CNXCTX_H
    3939#define _CNXCTX_H
     40
     41/* Maximum time we allow a connection to be blocked because of head-of-the-line buffers. After this delay, connection is considered in error. */
     42#define MAX_HOTL_BLOCKING_TIME  1000    /* ms */
    4043
    4144/* The connection context structure */
  • libfdcore/sctp.c

    r1198 r1200  
    10841084#endif /* OLD_SCTP_SOCKET_API */
    10851085        ssize_t ret;
    1086         int timedout = 0;
     1086        struct timespec ts, now;
    10871087       
    10881088        TRACE_ENTRY("%p %hu %p %d", conn, strid, iov, iovcnt);
    10891089        CHECK_PARAMS_DO(conn && iov && iovcnt, { errno = EINVAL; return -1; } );
     1090        CHECK_SYS_DO(  clock_gettime(CLOCK_REALTIME, &ts), return -1 );
    10901091       
    10911092        memset(&mhdr, 0, sizeof(mhdr));
     
    11211122        if ((ret < 0) && ((errno == EAGAIN) || (errno == EINTR))) {
    11221123                pthread_testcancel();
    1123                 if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING ))
     1124                /* Check how much time we were blocked for this sending. */
     1125                CHECK_SYS_DO(  clock_gettime(CLOCK_REALTIME, &now), return -1 );
     1126                if ( ((now.tv_sec - ts.tv_sec) * 1000 + ((now.tv_nsec - ts.tv_nsec) / 1000000L)) > MAX_HOTL_BLOCKING_TIME) {
     1127                        LOG_D("Unable to send any data for %dms, closing the connection", MAX_HOTL_BLOCKING_TIME);
     1128                } else if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING )) {
    11241129                        goto again; /* don't care, just ignore */
    1125                 if (!timedout) {
    1126                         timedout ++; /* allow for one timeout while closing */
    1127                         goto again;
    1128                 }
     1130                }
     1131               
     1132                /* propagate the error */
     1133                errno = -ret;
     1134                ret = -1;
    11291135        }
    11301136       
Note: See TracChangeset for help on using the changeset viewer.