diff options
Diffstat (limited to 'src/resolve/resolved-dns-stream.c')
-rw-r--r-- | src/resolve/resolved-dns-stream.c | 55 |
1 files changed, 12 insertions, 43 deletions
diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c index 5c4a9ebb99..61e92bea83 100644 --- a/src/resolve/resolved-dns-stream.c +++ b/src/resolve/resolved-dns-stream.c @@ -279,7 +279,7 @@ static DnsPacket *dns_stream_take_read_packet(DnsStream *s) { * Even this makes a room to read in the stream, this does not call dns_stream_update(), hence * EPOLLIN flag is not set automatically. So, to read further packets from the stream, * dns_stream_update() must be called explicitly. Currently, this is only called from - * on_stream_io_impl(), and there dns_stream_update() is called. */ + * on_stream_io(), and there dns_stream_update() is called. */ if (!s->read_packet) return NULL; @@ -294,15 +294,13 @@ static DnsPacket *dns_stream_take_read_packet(DnsStream *s) { return TAKE_PTR(s->read_packet); } -static int on_stream_io_impl(DnsStream *s, uint32_t revents) { +static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + _cleanup_(dns_stream_unrefp) DnsStream *s = dns_stream_ref(userdata); /* Protect stream while we process it */ bool progressed = false; int r; assert(s); - /* This returns 1 when possible remaining stream exists, 0 on completed - stream or recoverable error, and negative errno on failure. */ - #if ENABLE_DNS_OVER_TLS if (s->encrypted) { r = dnstls_stream_on_io(s, revents); @@ -354,9 +352,9 @@ static int on_stream_io_impl(DnsStream *s, uint32_t revents) { } } - if ((revents & (EPOLLIN|EPOLLHUP|EPOLLRDHUP)) && - (!s->read_packet || - s->n_read < sizeof(s->read_size) + s->read_packet->size)) { + while ((revents & (EPOLLIN|EPOLLHUP|EPOLLRDHUP)) && + (!s->read_packet || + s->n_read < sizeof(s->read_size) + s->read_packet->size)) { if (s->n_read < sizeof(s->read_size)) { ssize_t ss; @@ -365,6 +363,7 @@ static int on_stream_io_impl(DnsStream *s, uint32_t revents) { if (ss < 0) { if (!ERRNO_IS_TRANSIENT(ss)) return dns_stream_complete(s, -ss); + break; } else if (ss == 0) return dns_stream_complete(s, ECONNRESET); else { @@ -418,6 +417,7 @@ static int on_stream_io_impl(DnsStream *s, uint32_t revents) { if (ss < 0) { if (!ERRNO_IS_TRANSIENT(ss)) return dns_stream_complete(s, -ss); + break; } else if (ss == 0) return dns_stream_complete(s, ECONNRESET); else @@ -438,6 +438,10 @@ static int on_stream_io_impl(DnsStream *s, uint32_t revents) { return dns_stream_complete(s, -r); s->packet_received = true; + + /* If we just disabled the read event, stop reading */ + if (!FLAGS_SET(s->requested_events, EPOLLIN)) + break; } } } @@ -455,41 +459,6 @@ static int on_stream_io_impl(DnsStream *s, uint32_t revents) { log_warning_errno(errno, "Couldn't restart TCP connection timeout, ignoring: %m"); } - return 1; -} - -static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *userdata) { - _cleanup_(dns_stream_unrefp) DnsStream *s = dns_stream_ref(userdata); /* Protect stream while we process it */ - int r; - - assert(s); - - r = on_stream_io_impl(s, revents); - if (r <= 0) - return r; - -#if ENABLE_DNS_OVER_TLS - if (!s->encrypted) - return 0; - - /* When using DNS-over-TLS, the underlying TLS library may read the entire TLS record - and buffer it internally. If this happens, we will not receive further EPOLLIN events, - and unless there's some unrelated activity on the socket, we will hang until time out. - To avoid this, if there's buffered TLS data, generate a "fake" EPOLLIN event. - This is hacky, but it makes this case transparent to the rest of the IO code. */ - while (dnstls_stream_has_buffered_data(s)) { - uint32_t events; - - /* Make sure the stream still wants to process more data... */ - if (!FLAGS_SET(s->requested_events, EPOLLIN)) - break; - - r = on_stream_io_impl(s, EPOLLIN); - if (r <= 0) - return r; - } -#endif - return 0; } |