Hi!

On Wed, 2017-12-13 at 07:42 +0100, Claudio Jeker wrote:
> I have seen something similar and came to the conclusion that the
> timeout
> handling of relayd is not correct. As long as traffic is flowing the
> timeout should be reset (at least that is what every other
> implementation
> does). This is not really happening in relayd. I have seen this on
> GET
> requests that are huge (timeout hits in the middle of the transimit
> and
> kills the session).
> 
> Because of this I think the diff is a workaround and does not solve
> the
> real underlying problem.

My next try. It schedules a timer event to bump bufferevent timeouts.
One of the possibilities is to schedule it eg once every second, but I
choose to schedule the event at half of the remaining bufferevent
timeout.

Rivo

Index: usr.sbin/relayd/relay.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relay.c,v
retrieving revision 1.236
diff -u -p -r1.236 relay.c
--- usr.sbin/relayd/relay.c     28 Nov 2017 01:51:47 -0000      1.236
+++ usr.sbin/relayd/relay.c     16 Dec 2017 00:36:31 -0000
@@ -69,6 +69,7 @@ int            relay_socket_connect(struct sockad
 
 void            relay_accept(int, short, void *);
 void            relay_input(struct rsession *);
+void            relay_timeout(int, short, void *);
 
 void            relay_hash_addr(SIPHASH_CTX *, struct sockaddr_storage *, int);
 
@@ -662,6 +663,7 @@ relay_connected(int fd, short sig, void 
        struct bufferevent      *bev;
        struct ctl_relay_event  *out = &con->se_out;
        socklen_t                len;
+       struct timeval           tv;
        int                      error;
 
        if (sig == EV_TIMEOUT) {
@@ -724,6 +726,14 @@ relay_connected(int fd, short sig, void 
 
        bufferevent_settimeout(bev,
            rlay->rl_conf.timeout.tv_sec, rlay->rl_conf.timeout.tv_sec);
+
+       evtimer_set(&con->se_ev, relay_timeout, con);
+       timerclear(&tv);
+       tv.tv_sec = rlay->rl_conf.timeout.tv_sec / 2;
+       if (tv.tv_sec == 0)
+               tv.tv_usec = 500000;
+       evtimer_add(&con->se_ev, &tv);
+
        bufferevent_setwatermark(bev, EV_WRITE,
                RELAY_MIN_PREFETCHED * proto->tcpbufsiz, 0);
        bufferevent_enable(bev, EV_READ|EV_WRITE);
@@ -955,6 +965,38 @@ relay_spliceadjust(struct ctl_relay_even
        cre->splicelen = -1;
 
        return (0);
+}
+
+void
+relay_timeout(int fd, short event, void *arg)
+{
+       struct rsession         *con = arg;
+       struct ctl_relay_event  *cre = &con->se_out;
+       struct relay            *rlay = con->se_relay;
+       struct timeval           tv, tv_now;
+       time_t                   timeout;
+
+       timerclear(&tv);
+       getmonotime(&tv_now);
+       timersub(&tv_now, &con->se_tv_last, &tv);
+       timeout = rlay->rl_conf.timeout.tv_sec - tv.tv_sec;
+
+       DPRINTF("%s: session %d: last %llds ago, timeout %llds", __func__,
+           con->se_id, tv.tv_sec, timeout);
+
+       if (timeout > 0){
+               bufferevent_settimeout(cre->bev, timeout, timeout);
+               bufferevent_settimeout(con->se_in.bev, timeout, timeout);
+       }
+
+       evtimer_set(&con->se_ev, relay_timeout, con);
+       tv.tv_sec = (rlay->rl_conf.timeout.tv_sec - tv.tv_sec) / 2;
+       if (tv.tv_sec == 0)
+               tv.tv_usec = 500000;
+       evtimer_add(&con->se_ev, &tv);
+
+       DPRINTF("%s: session %d: next after %llds", __func__, con->se_id,
+           tv.tv_sec);
 }
 
 void

Reply via email to