Hi,

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.

ok?

bluhm


Index: usr.sbin/relayd//parse.y
===================================================================
RCS file: /data/mirror/openbsd/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    3 Sep 2011 00:11:25 -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: /data/mirror/openbsd/cvs/src/usr.sbin/relayd/relay.c,v
retrieving revision 1.138
diff -u -p -r1.138 relay.c
--- usr.sbin/relayd//relay.c    20 May 2011 09:43:53 -0000      1.138
+++ usr.sbin/relayd//relay.c    2 Sep 2011 23:53:48 -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_READ|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)) {
@@ -1898,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