From cef37f15460945d121ad7ea7fb260548d3596228 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 1 Jan 2015 15:02:32 +0200 Subject: [PATCH] tcp: fix unfulfilled read promise on RST A user may be waiting for data, but we never we never notify them if we receive an RST. As a result the tcb, connection, and any user data structures will hang around in memory. Fix by notifying the user if they are waiting, and marking the connection as nuked so they don't try to read again. Reviewed-by: Asias He --- net/tcp.hh | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/net/tcp.hh b/net/tcp.hh index f79391ceb1..bf69d6fe52 100644 --- a/net/tcp.hh +++ b/net/tcp.hh @@ -158,6 +158,8 @@ private: bool _local_fin_sent = false; bool _local_fin_acked = false; bool _foreign_fin_received = false; + // Connection was reset by peer + bool _nuked = false; tcp& _tcp; connection* _conn = nullptr; ipaddr _local_ip; @@ -506,7 +508,19 @@ void tcp::tcb::input(tcp_hdr* th, packet p) { auto seg_len = p.len(); if (th->f_rst) { + // Fake end-of-connection so reads return immediately + _nuked = true; cleanup(); + if (_rcv._data_received_promise) { + // FIXME: set_exception() instead? + _rcv._data_received_promise->set_value(); + _rcv._data_received_promise = {}; + } + if (_snd._all_data_acked_promise) { + // FIXME: set_exception() instead? + _snd._all_data_acked_promise->set_value(); + _snd._all_data_acked_promise = {}; + } return; } if (th->f_syn) { @@ -791,6 +805,9 @@ packet tcp::tcb::get_transmit_packet() { template void tcp::tcb::output() { + if (_nuked) { + return; + } do { uint8_t options_size = 0; packet p = get_transmit_packet(); @@ -863,7 +880,7 @@ void tcp::tcb::output() { template future<> tcp::tcb::wait_for_data() { - if (!_rcv.data.empty() || _foreign_fin_received) { + if (!_rcv.data.empty() || _foreign_fin_received || _nuked) { return make_ready_future<>(); } _rcv._data_received_promise = promise<>();