On Sat, Sep 03, 2011 at 02:25:37AM +0200, Alexander Bluhm wrote:
> During socket splicing the relayd session timeouts could not be
> measured exactly in user land.  Use the new idle timeout for socket
> splicing in the kernel to make it correct.

I think, I got the flag handling wrong.  Make sure that the error
flag is set.

-+      if (error & (EVBUFFER_READ|EVBUFFER_ERROR) && errno == ETIMEDOUT) {
++      if (error & EVBUFFER_ERROR && errno == ETIMEDOUT) {

Updated diff below.

bluhm


Index: usr.sbin/relayd/parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/parse.y,v
retrieving revision 1.158
diff -u -p -r1.158 parse.y
--- usr.sbin/relayd/parse.y     26 May 2011 14:48:20 -0000      1.158
+++ usr.sbin/relayd/parse.y     4 Sep 2011 11:22:59 -0000
@@ -833,13 +833,6 @@ proto              : relay_proto PROTO STRING      {
                        p->type = $1;
                        p->cache = RELAY_CACHESIZE;
                        p->tcpflags = TCPFLAG_DEFAULT;
-                       if (p->type != RELAY_PROTO_TCP) {
-                               /*
-                                * Splicing is currently only supported
-                                * for plain TCP relays.
-                                */
-                               p->tcpflags |= TCPFLAG_NSPLICE;
-                       }
                        p->sslflags = SSLFLAG_DEFAULT;
                        p->tcpbacklog = RELAY_BACKLOG;
                        (void)strlcpy(p->sslciphers, SSLCIPHERS_DEFAULT,
Index: usr.sbin/relayd/relay.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relay.c,v
retrieving revision 1.140
diff -u -p -r1.140 relay.c
--- usr.sbin/relayd/relay.c     4 Sep 2011 10:42:47 -0000       1.140
+++ usr.sbin/relayd/relay.c     4 Sep 2011 11:23:03 -0000
@@ -77,10 +77,12 @@ u_int32_t    relay_hash_addr(struct sockad
 
 void            relay_write(struct bufferevent *, void *);
 void            relay_read(struct bufferevent *, void *);
-int             relay_splicelen(struct ctl_relay_event *);
 void            relay_error(struct bufferevent *, short, void *);
 void            relay_dump(struct ctl_relay_event *, const void *, size_t);
 
+int             relay_splice(struct ctl_relay_event *);
+int             relay_splicelen(struct ctl_relay_event *);
+
 int             relay_resolve(struct ctl_relay_event *,
                    struct protonode *, struct protonode *);
 int             relay_handle_http(struct ctl_relay_event *,
@@ -675,26 +677,10 @@ relay_connected(int fd, short sig, void 
                }
                break;
        case RELAY_PROTO_TCP:
-               if ((proto->tcpflags & TCPFLAG_NSPLICE) ||
-                   (rlay->rl_conf.flags & (F_SSL|F_SSLCLIENT)))
-                       break;
-               if (setsockopt(con->se_in.s, SOL_SOCKET, SO_SPLICE,
-                   &con->se_out.s, sizeof(int)) == -1) {
-                       log_debug("%s: session %d: splice forward failed: %s",
-                           __func__, con->se_id, strerror(errno));
-                       return;
-               }
-               con->se_in.splicelen = 0;
-               if (setsockopt(con->se_out.s, SOL_SOCKET, SO_SPLICE,
-                   &con->se_in.s, sizeof(int)) == -1) {
-                       log_debug("%s: session %d: splice backward failed: %s",
-                           __func__, con->se_id, strerror(errno));
-                       return;
-               }
-               con->se_out.splicelen = 0;
+               /* Use defaults */
                break;
        default:
-               fatalx("relay_input: unknown protocol");
+               fatalx("relay_connected: unknown protocol");
        }
 
        /*
@@ -719,6 +705,9 @@ relay_connected(int fd, short sig, void 
        bufferevent_settimeout(bev,
            rlay->rl_conf.timeout.tv_sec, rlay->rl_conf.timeout.tv_sec);
        bufferevent_enable(bev, EV_READ|EV_WRITE);
+
+       if (relay_splice(&con->se_out) == -1)
+               relay_close(con, strerror(errno));
 }
 
 void
@@ -766,6 +755,9 @@ relay_input(struct rsession *con)
        bufferevent_settimeout(con->se_in.bev,
            rlay->rl_conf.timeout.tv_sec, rlay->rl_conf.timeout.tv_sec);
        bufferevent_enable(con->se_in.bev, EV_READ|EV_WRITE);
+
+       if (relay_splice(&con->se_in) == -1)
+               relay_close(con, strerror(errno));
 }
 
 void
@@ -1842,16 +1834,46 @@ relay_close_http(struct rsession *con, u
 }
 
 int
+relay_splice(struct ctl_relay_event *cre)
+{
+       struct rsession         *con = cre->con;
+       struct relay            *rlay = (struct relay *)con->se_relay;
+       struct protocol         *proto = rlay->rl_proto;
+       struct splice            sp;
+
+       if ((rlay->rl_conf.flags & (F_SSL|F_SSLCLIENT)) ||
+           (proto->tcpflags & TCPFLAG_NSPLICE))
+               return (0);
+
+       if (cre->bev->readcb != relay_read)
+               return (0);
+
+       bzero(&sp, sizeof(sp));
+       sp.sp_fd = cre->dst->s;
+       sp.sp_idle = rlay->rl_conf.timeout;
+       if (setsockopt(cre->s, SOL_SOCKET, SO_SPLICE, &sp, sizeof(sp)) == -1) {
+               log_debug("%s: session %d: splice dir %d failed: %s",
+                   __func__, con->se_id, cre->dir, strerror(errno));
+               return (-1);
+       }
+       cre->splicelen = 0;
+       DPRINTF("%s: session %d: splice dir %d successful",
+           __func__, con->se_id, cre->dir);
+       return (1);
+}
+
+int
 relay_splicelen(struct ctl_relay_event *cre)
 {
-       struct rsession *con = cre->con;
-       off_t len;
-       socklen_t optlen;
+       struct rsession         *con = cre->con;
+       off_t                    len;
+       socklen_t                optlen;
 
        optlen = sizeof(len);
        if (getsockopt(cre->s, SOL_SOCKET, SO_SPLICE, &len, &optlen) == -1) {
-               relay_close(con, strerror(errno));
-               return (0);
+               log_debug("%s: session %d: splice dir %d get length failed: %s",
+                   __func__, con->se_id, cre->dir, strerror(errno));
+               return (-1);
        }
        if (len > cre->splicelen) {
                cre->splicelen = len;
@@ -1866,22 +1888,41 @@ relay_error(struct bufferevent *bev, sho
        struct ctl_relay_event *cre = (struct ctl_relay_event *)arg;
        struct rsession *con = cre->con;
        struct evbuffer *dst;
-       struct timeval tv, tv_now;
 
        if (error & EVBUFFER_TIMEOUT) {
-               if (gettimeofday(&tv_now, NULL) == -1) {
-                       relay_close(con, strerror(errno));
-                       return;
-               }
-               if (cre->splicelen >= 0 && relay_splicelen(cre))
-                       con->se_tv_last = tv_now;
-               if (cre->dst->splicelen >= 0 && relay_splicelen(cre->dst))
-                       con->se_tv_last = tv_now;
-               timersub(&tv_now, &con->se_tv_last, &tv);
-               if (timercmp(&tv, &con->se_relay->rl_conf.timeout, >=))
+               if (cre->splicelen >= 0) {
+                       bufferevent_enable(bev, EV_READ);
+               } else if (cre->dst->splicelen >= 0) {
+                       switch (relay_splicelen(cre->dst)) {
+                       case -1:
+                               goto fail;
+                       case 0:
+                               relay_close(con, "buffer event timeout");
+                               break;
+                       case 1:
+                               bufferevent_enable(bev, EV_READ);
+                               break;
+                       }
+               } else {
                        relay_close(con, "buffer event timeout");
-               else
-                       bufferevent_enable(cre->bev, EV_READ);
+               }
+               return;
+       }
+       if (error & EVBUFFER_ERROR && errno == ETIMEDOUT) {
+               if (cre->dst->splicelen >= 0) {
+                       switch (relay_splicelen(cre->dst)) {
+                       case -1:
+                               goto fail;
+                       case 0:
+                               relay_close(con, "splice timeout");
+                               return;
+                       case 1:
+                               bufferevent_enable(bev, EV_READ);
+                               break;
+                       }
+               }
+               if (relay_splice(cre) == -1)
+                       goto fail;
                return;
        }
        if (error & (EVBUFFER_READ|EVBUFFER_WRITE|EVBUFFER_EOF)) {
@@ -1899,6 +1940,9 @@ relay_error(struct bufferevent *bev, sho
                return;
        }
        relay_close(con, "buffer event error");
+       return;
+ fail:
+       relay_close(con, strerror(errno));
 }
 
 void

Reply via email to