summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGunnar Beutner <gbeutner@serenityos.org>2022-11-01 10:04:13 +0100
committerLinus Groh <mail@linusgroh.de>2022-11-01 14:31:48 +0000
commita9888d4ea05b04cfb7f56ac4793670bb524de996 (patch)
treee697c6badf4ce1552120778ed7f737e8267f1c28
parentab8b04368476408c41d0a2cdf68e27358a4ca5f4 (diff)
downloadserenity-a9888d4ea05b04cfb7f56ac4793670bb524de996.zip
AK+Kernel: Handle some allocation failures in IPv4Socket and TCPSocket
This adds try_* methods to AK::SinglyLinkedList and AK::SinglyLinkedListWithCount and updates the network stack to use those to gracefully handle allocation failures. Refs #6369.
-rw-r--r--AK/SinglyLinkedList.h67
-rw-r--r--AK/SinglyLinkedListWithCount.h14
-rw-r--r--Kernel/Net/IPv4Socket.cpp6
-rw-r--r--Kernel/Net/TCPSocket.cpp25
4 files changed, 87 insertions, 25 deletions
diff --git a/AK/SinglyLinkedList.h b/AK/SinglyLinkedList.h
index 79babf10e5..11a574495f 100644
--- a/AK/SinglyLinkedList.h
+++ b/AK/SinglyLinkedList.h
@@ -7,6 +7,7 @@
#pragma once
#include <AK/Assertions.h>
+#include <AK/Error.h>
#include <AK/Find.h>
#include <AK/StdLibExtras.h>
#include <AK/Traits.h>
@@ -148,31 +149,51 @@ public:
}
template<typename U = T>
- void append(U&& value)
+ ErrorOr<void> try_append(U&& value)
{
- auto* node = new Node(forward<U>(value));
+ auto* node = new (nothrow) Node(forward<U>(value));
+ if (!node)
+ return Error::from_errno(ENOMEM);
if (!m_head) {
m_head = node;
m_tail = node;
- return;
+ return {};
}
m_tail->next = node;
m_tail = node;
+ return {};
}
template<typename U = T>
- void prepend(U&& value)
+ ErrorOr<void> try_prepend(U&& value)
{
- auto* node = new Node(forward<U>(value));
+ auto* node = new (nothrow) Node(forward<U>(value));
+ if (!node)
+ return Error::from_errno(ENOMEM);
if (!m_head) {
m_head = node;
m_tail = node;
- return;
+ return {};
}
node->next = m_head;
m_head = node;
+ return {};
+ }
+
+#ifndef KERNEL
+ template<typename U = T>
+ void append(U&& value)
+ {
+ MUST(try_append(forward<U>(value)));
}
+ template<typename U = T>
+ void prepend(U&& value)
+ {
+ MUST(try_prepend(forward<U>(value)));
+ }
+#endif
+
bool contains_slow(const T& value) const
{
return find(value) != end();
@@ -211,32 +232,50 @@ public:
}
template<typename U = T>
- void insert_before(Iterator iterator, U&& value)
+ ErrorOr<void> try_insert_before(Iterator iterator, U&& value)
{
- auto* node = new Node(forward<U>(value));
+ auto* node = new (nothrow) Node(forward<U>(value));
+ if (!node)
+ return Error::from_errno(ENOMEM);
node->next = iterator.m_node;
if (m_head == iterator.m_node)
m_head = node;
if (iterator.m_prev)
iterator.m_prev->next = node;
+ return {};
}
template<typename U = T>
- void insert_after(Iterator iterator, U&& value)
+ ErrorOr<void> try_insert_after(Iterator iterator, U&& value)
{
- if (iterator.is_end()) {
- append(value);
- return;
- }
+ if (iterator.is_end())
+ return try_append(value);
- auto* node = new Node(forward<U>(value));
+ auto* node = new (nothrow) Node(forward<U>(value));
+ if (!node)
+ return Error::from_errno(ENOMEM);
node->next = iterator.m_node->next;
iterator.m_node->next = node;
if (m_tail == iterator.m_node)
m_tail = node;
+ return {};
+ }
+
+#ifndef KERNEL
+ template<typename U = T>
+ void insert_before(Iterator iterator, U&& value)
+ {
+ MUST(try_insert_before(iterator, forward<U>(value)));
+ }
+
+ template<typename U = T>
+ void insert_after(Iterator iterator, U&& value)
+ {
+ MUST(try_insert_after(iterator, forward<U>(value)));
}
+#endif
void remove(Iterator& iterator)
{
diff --git a/AK/SinglyLinkedListWithCount.h b/AK/SinglyLinkedListWithCount.h
index 4f47ef7a24..39de628610 100644
--- a/AK/SinglyLinkedListWithCount.h
+++ b/AK/SinglyLinkedListWithCount.h
@@ -60,11 +60,21 @@ public:
}
template<typename U = T>
+ ErrorOr<void> try_append(U&& value)
+ {
+ auto result = List::try_append(forward<T>(value));
+ if (!result.is_error())
+ m_count++;
+ return result;
+ }
+
+#ifndef KERNEL
+ template<typename U = T>
void append(U&& value)
{
- m_count++;
- return List::append(forward<T>(value));
+ MUST(try_append(forward<T>(value)));
}
+#endif
bool contains_slow(const T& value) const
{
diff --git a/Kernel/Net/IPv4Socket.cpp b/Kernel/Net/IPv4Socket.cpp
index d18a08d795..5b66152ea7 100644
--- a/Kernel/Net/IPv4Socket.cpp
+++ b/Kernel/Net/IPv4Socket.cpp
@@ -449,7 +449,11 @@ bool IPv4Socket::did_receive(IPv4Address const& source_address, u16 source_port,
dbgln("IPv4Socket: did_receive unable to allocate storage for incoming packet.");
return false;
}
- m_receive_queue.append({ source_address, source_port, packet_timestamp, data_or_error.release_value() });
+ auto result = m_receive_queue.try_append({ source_address, source_port, packet_timestamp, data_or_error.release_value() });
+ if (result.is_error()) {
+ dbgln("IPv4Socket: Dropped incoming packet because appending to the receive queue failed.");
+ return false;
+ }
set_can_read(true);
}
m_bytes_received += packet_size;
diff --git a/Kernel/Net/TCPSocket.cpp b/Kernel/Net/TCPSocket.cpp
index b19e450f49..2cd19f5137 100644
--- a/Kernel/Net/TCPSocket.cpp
+++ b/Kernel/Net/TCPSocket.cpp
@@ -274,20 +274,29 @@ ErrorOr<void> TCPSocket::send_tcp_packet(u16 flags, UserOrKernelBuffer const* pa
tcp_packet.set_checksum(compute_tcp_checksum(local_address(), peer_address(), tcp_packet, payload_size));
- routing_decision.adapter->send_packet(packet->bytes());
-
- m_packets_out++;
- m_bytes_out += buffer_size;
- if (tcp_packet.has_syn() || payload_size > 0) {
+ bool expect_ack { tcp_packet.has_syn() || payload_size > 0 };
+ if (expect_ack) {
+ bool append_failed { false };
m_unacked_packets.with_exclusive([&](auto& unacked_packets) {
- unacked_packets.packets.append({ m_sequence_number, move(packet), ipv4_payload_offset, *routing_decision.adapter });
+ auto result = unacked_packets.packets.try_append({ m_sequence_number, packet, ipv4_payload_offset, *routing_decision.adapter });
+ if (result.is_error()) {
+ dbgln("TCPSocket: Dropped outbound packet because try_append() failed");
+ append_failed = true;
+ return;
+ }
unacked_packets.size += payload_size;
enqueue_for_retransmit();
});
- } else {
- routing_decision.adapter->release_packet_buffer(*packet);
+ if (append_failed)
+ return set_so_error(ENOMEM);
}
+ m_packets_out++;
+ m_bytes_out += buffer_size;
+ routing_decision.adapter->send_packet(packet->bytes());
+ if (!expect_ack)
+ routing_decision.adapter->release_packet_buffer(*packet);
+
return {};
}