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