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 <asias@cloudius-systems.com>
This commit is contained in:
19
net/tcp.hh
19
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<InetTraits>::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<InetTraits>::tcb::get_transmit_packet() {
|
||||
|
||||
template <typename InetTraits>
|
||||
void tcp<InetTraits>::tcb::output() {
|
||||
if (_nuked) {
|
||||
return;
|
||||
}
|
||||
do {
|
||||
uint8_t options_size = 0;
|
||||
packet p = get_transmit_packet();
|
||||
@@ -863,7 +880,7 @@ void tcp<InetTraits>::tcb::output() {
|
||||
|
||||
template <typename InetTraits>
|
||||
future<> tcp<InetTraits>::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<>();
|
||||
|
||||
Reference in New Issue
Block a user