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