summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorIwan Timmer <irtimmer@gmail.com>2018-04-27 13:20:31 +0200
committerIwan Timmer <irtimmer@gmail.com>2018-06-11 21:35:58 +0200
commit91ccab1e40a10963764f449ba8309d47e90d6a8a (patch)
tree2fbebf8b1850525c1ed2d81b46887e916ffbb157 /src
parentresolved: longlived TCP connections (diff)
downloadsystemd-91ccab1e40a10963764f449ba8309d47e90d6a8a.tar.xz
systemd-91ccab1e40a10963764f449ba8309d47e90d6a8a.zip
resolved: TCP fast open connections
Add suport for TCP fast open connection to reduce latency for successive DNS request over TCP
Diffstat (limited to 'src')
-rw-r--r--src/resolve/resolved-dns-scope.c25
-rw-r--r--src/resolve/resolved-dns-scope.h2
-rw-r--r--src/resolve/resolved-dns-stream.c51
-rw-r--r--src/resolve/resolved-dns-stream.h6
-rw-r--r--src/resolve/resolved-dns-stub.c2
-rw-r--r--src/resolve/resolved-dns-transaction.c9
-rw-r--r--src/resolve/resolved-llmnr.c2
7 files changed, 76 insertions, 21 deletions
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index 763789c450..b92bcd557e 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -306,10 +306,11 @@ static int dns_scope_socket(
int family,
const union in_addr_union *address,
DnsServer *server,
- uint16_t port) {
+ uint16_t port,
+ union sockaddr_union *ret_socket_address) {
_cleanup_close_ int fd = -1;
- union sockaddr_union sa = {};
+ union sockaddr_union sa;
socklen_t salen;
static const int one = 1;
int r, ifindex;
@@ -392,19 +393,27 @@ static int dns_scope_socket(
}
}
- r = connect(fd, &sa.sa, salen);
- if (r < 0 && errno != EINPROGRESS)
- return -errno;
+ if (ret_socket_address)
+ *ret_socket_address = sa;
+ else {
+ r = connect(fd, &sa.sa, salen);
+ if (r < 0 && errno != EINPROGRESS)
+ return -errno;
+ }
return TAKE_FD(fd);
}
int dns_scope_socket_udp(DnsScope *s, DnsServer *server, uint16_t port) {
- return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, server, port);
+ return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, server, port, NULL);
}
-int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port) {
- return dns_scope_socket(s, SOCK_STREAM, family, address, server, port);
+int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port, union sockaddr_union *ret_socket_address) {
+ /* If ret_socket_address is not NULL, the caller is responisble
+ * for calling connect() or sendmsg(). This is required by TCP
+ * Fast Open, to be able to send the initial SYN packet along
+ * with the first data packet. */
+ return dns_scope_socket(s, SOCK_STREAM, family, address, server, port, ret_socket_address);
}
DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain) {
diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h
index 15c58251d0..0042193e20 100644
--- a/src/resolve/resolved-dns-scope.h
+++ b/src/resolve/resolved-dns-scope.h
@@ -75,7 +75,7 @@ void dns_scope_packet_received(DnsScope *s, usec_t rtt);
void dns_scope_packet_lost(DnsScope *s, usec_t usec);
int dns_scope_emit_udp(DnsScope *s, int fd, DnsPacket *p);
-int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port);
+int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port, union sockaddr_union *ret_socket_address);
int dns_scope_socket_udp(DnsScope *s, DnsServer *server, uint16_t port);
DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain);
diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c
index f537fe6ab4..5d2cc1ad8b 100644
--- a/src/resolve/resolved-dns-stream.c
+++ b/src/resolve/resolved-dns-stream.c
@@ -182,6 +182,39 @@ static int dns_stream_identify(DnsStream *s) {
return 0;
}
+static ssize_t dns_stream_writev(DnsStream *s, const struct iovec *iov, size_t iovcnt) {
+ ssize_t r;
+
+ assert(s);
+ assert(iov);
+
+ if (s->tfo_salen > 0) {
+ struct msghdr hdr = {
+ .msg_iov = (struct iovec*) iov,
+ .msg_iovlen = iovcnt,
+ .msg_name = &s->tfo_address.sa,
+ .msg_namelen = s->tfo_salen
+ };
+
+ r = sendmsg(s->fd, &hdr, MSG_FASTOPEN);
+ if (r < 0) {
+ if (errno == EOPNOTSUPP) {
+ s->tfo_salen = 0;
+ r = connect(s->fd, &s->tfo_address.sa, s->tfo_salen);
+ if (r < 0)
+ return -errno;
+
+ r = -EAGAIN;
+ } else if (errno == EINPROGRESS)
+ r = -EAGAIN;
+ } else
+ s->tfo_salen = 0; /* connection is made */
+ } else
+ r = writev(s->fd, iov, iovcnt);
+
+ return r;
+}
+
static int on_stream_timeout(sd_event_source *es, usec_t usec, void *userdata) {
DnsStream *s = userdata;
@@ -196,9 +229,12 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
assert(s);
- r = dns_stream_identify(s);
- if (r < 0)
- return dns_stream_complete(s, -r);
+ /* only identify after connecting */
+ if (s->tfo_salen == 0) {
+ r = dns_stream_identify(s);
+ if (r < 0)
+ return dns_stream_complete(s, -r);
+ }
if ((revents & EPOLLOUT) &&
s->write_packet &&
@@ -214,7 +250,7 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
IOVEC_INCREMENT(iov, 2, s->n_written);
- ss = writev(fd, iov, 2);
+ ss = dns_stream_writev(s, iov, 2);
if (ss < 0) {
if (!IN_SET(errno, EINTR, EAGAIN))
return dns_stream_complete(s, errno);
@@ -366,7 +402,7 @@ DnsStream *dns_stream_ref(DnsStream *s) {
return s;
}
-int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd) {
+int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd, const union sockaddr_union *tfo_address) {
_cleanup_(dns_stream_unrefp) DnsStream *s = NULL;
int r;
@@ -408,6 +444,11 @@ int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd) {
LIST_PREPEND(streams, m->dns_streams, s);
s->manager = m;
s->fd = fd;
+ if (tfo_address) {
+ s->tfo_address = *tfo_address;
+ s->tfo_salen = tfo_address->sa.sa_family == AF_INET6 ? sizeof(tfo_address->in6) : sizeof(tfo_address->in);
+ }
+
m->n_dns_streams++;
*ret = TAKE_PTR(s);
diff --git a/src/resolve/resolved-dns-stream.h b/src/resolve/resolved-dns-stream.h
index f392c13b0b..5ba2bd1814 100644
--- a/src/resolve/resolved-dns-stream.h
+++ b/src/resolve/resolved-dns-stream.h
@@ -37,6 +37,10 @@ struct DnsStream {
uint32_t ttl;
bool identified;
+ /* only when using TCP fast open */
+ union sockaddr_union tfo_address;
+ socklen_t tfo_salen;
+
sd_event_source *io_event_source;
sd_event_source *timeout_event_source;
@@ -55,7 +59,7 @@ struct DnsStream {
LIST_FIELDS(DnsStream, streams);
};
-int dns_stream_new(Manager *m, DnsStream **s, DnsProtocol protocol, int fd);
+int dns_stream_new(Manager *m, DnsStream **s, DnsProtocol protocol, int fd, const union sockaddr_union *tfo_address);
DnsStream *dns_stream_unref(DnsStream *s);
DnsStream *dns_stream_ref(DnsStream *s);
diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c
index 6b47a48df6..298d8132be 100644
--- a/src/resolve/resolved-dns-stub.c
+++ b/src/resolve/resolved-dns-stub.c
@@ -469,7 +469,7 @@ static int on_dns_stub_stream(sd_event_source *s, int fd, uint32_t revents, void
return -errno;
}
- r = dns_stream_new(m, &stream, DNS_PROTOCOL_DNS, cfd);
+ r = dns_stream_new(m, &stream, DNS_PROTOCOL_DNS, cfd, NULL);
if (r < 0) {
safe_close(cfd);
return r;
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 5d3f6bae27..5e4125cac5 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -557,6 +557,7 @@ static int dns_stream_on_packet(DnsStream *s) {
static int dns_transaction_emit_tcp(DnsTransaction *t) {
_cleanup_close_ int fd = -1;
_cleanup_(dns_stream_unrefp) DnsStream *s = NULL;
+ union sockaddr_union sa;
int r;
assert(t);
@@ -580,14 +581,14 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
if (t->server->stream)
s = dns_stream_ref(t->server->stream);
else
- fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, 53);
+ fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, 53, &sa);
break;
case DNS_PROTOCOL_LLMNR:
/* When we already received a reply to this (but it was truncated), send to its sender address */
if (t->received)
- fd = dns_scope_socket_tcp(t->scope, t->received->family, &t->received->sender, NULL, t->received->sender_port);
+ fd = dns_scope_socket_tcp(t->scope, t->received->family, &t->received->sender, NULL, t->received->sender_port, &sa);
else {
union in_addr_union address;
int family = AF_UNSPEC;
@@ -604,7 +605,7 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
if (family != t->scope->family)
return -ESRCH;
- fd = dns_scope_socket_tcp(t->scope, family, &address, NULL, LLMNR_PORT);
+ fd = dns_scope_socket_tcp(t->scope, family, &address, NULL, LLMNR_PORT, &sa);
}
break;
@@ -617,7 +618,7 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
if (fd < 0)
return fd;
- r = dns_stream_new(t->scope->manager, &s, t->scope->protocol, fd);
+ r = dns_stream_new(t->scope->manager, &s, t->scope->protocol, fd, &sa);
if (r < 0)
return r;
diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c
index ca49df8090..9eef59be0d 100644
--- a/src/resolve/resolved-llmnr.c
+++ b/src/resolve/resolved-llmnr.c
@@ -345,7 +345,7 @@ static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *u
return -errno;
}
- r = dns_stream_new(m, &stream, DNS_PROTOCOL_LLMNR, cfd);
+ r = dns_stream_new(m, &stream, DNS_PROTOCOL_LLMNR, cfd, NULL);
if (r < 0) {
safe_close(cfd);
return r;