On Tue, Mar 08, 2011 at 02:11:31AM +0100, Alexander Bluhm wrote: > Hmm, perhaps too small. There is a session timeout and relayctl > show sessions idle time. Relayd does not realize when the kernel > is transferring data automatically. It should check the splice > data length with getsockopt() periodically or when the timeout > fires.
This diff fixes the timeout issues. If a timeout occured and splicing is active, check wether the splice length has changed. If so, reset the timeout and idle counter. Thay may make timeout detection longer than without splicing. Socket splicing works for plain TCP conections now. I have tested that HTTP keep-alive and SSL are not affected. As requested by Theo splicing cannot be turned off. ok? bluhm Index: usr.sbin/relayd/relay.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/relayd/relay.c,v retrieving revision 1.130 diff -u -p -r1.130 relay.c --- usr.sbin/relayd/relay.c 12 Mar 2011 21:06:40 -0000 1.130 +++ usr.sbin/relayd/relay.c 16 Mar 2011 01:04:38 -0000 @@ -77,6 +77,7 @@ 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); @@ -1938,15 +1939,47 @@ relay_close_http(struct rsession *con, u } } +int +relay_splicelen(struct ctl_relay_event *cre) +{ + struct rsession *con = (struct rsession *)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); + } + if (len > cre->splicelen) { + cre->splicelen = len; + return (1); + } + return (0); +} + void relay_error(struct bufferevent *bev, short error, void *arg) { struct ctl_relay_event *cre = (struct ctl_relay_event *)arg; struct rsession *con = (struct rsession *)cre->con; struct evbuffer *dst; + struct timeval tv, tv_now; if (error & EVBUFFER_TIMEOUT) { - relay_close(con, "buffer event 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, >=)) + relay_close(con, "buffer event timeout"); + else + bufferevent_enable(cre->dst->bev, EV_READ); return; } if (error & (EVBUFFER_READ|EVBUFFER_WRITE|EVBUFFER_EOF)) { @@ -2000,6 +2033,8 @@ relay_accept(int fd, short sig, void *ar con->se_out.dst = &con->se_in; con->se_in.con = con; con->se_out.con = con; + con->se_in.splicelen = -1; + con->se_out.splicelen = -1; con->se_relay = rlay; con->se_id = ++relay_conid; con->se_relayid = rlay->rl_conf.id; @@ -2327,6 +2362,24 @@ relay_connect(struct rsession *con) log_debug("relay_connect: session %d: forward failed: %s", con->se_id, strerror(errno)); return (-1); + } + + if (rlay->rl_proto->type == RELAY_PROTO_TCP && + (rlay->rl_conf.flags & (F_SSL|F_SSLCLIENT)) == 0) { + if (setsockopt(con->se_in.s, SOL_SOCKET, SO_SPLICE, + &con->se_out.s, sizeof(int)) == -1) { + log_debug("relay_connect: session %d: splice forward " + "failed: %s", con->se_id, strerror(errno)); + return (-1); + } + con->se_in.splicelen = 0; + if (setsockopt(con->se_out.s, SOL_SOCKET, SO_SPLICE, + &con->se_in.s, sizeof(int)) == -1) { + log_debug("relay_connect: session %d: splice backward " + "failed: %s", con->se_id, strerror(errno)); + return (-1); + } + con->se_out.splicelen = 0; } if (errno == EINPROGRESS) Index: usr.sbin/relayd/relayd.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/relayd/relayd.h,v retrieving revision 1.140 diff -u -p -r1.140 relayd.h --- usr.sbin/relayd/relayd.h 31 Dec 2010 21:22:42 -0000 1.140 +++ usr.sbin/relayd/relayd.h 12 Mar 2011 19:54:53 -0000 @@ -162,6 +162,7 @@ struct ctl_relay_event { char *args; char *version; + off_t splicelen; int line; size_t toread; int chunked;