mirror of
https://github.com/RGBCube/serenity
synced 2025-07-02 19:42:14 +00:00
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.
This commit is contained in:
parent
ab8b043684
commit
a9888d4ea0
4 changed files with 92 additions and 30 deletions
|
@ -7,6 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Assertions.h>
|
#include <AK/Assertions.h>
|
||||||
|
#include <AK/Error.h>
|
||||||
#include <AK/Find.h>
|
#include <AK/Find.h>
|
||||||
#include <AK/StdLibExtras.h>
|
#include <AK/StdLibExtras.h>
|
||||||
#include <AK/Traits.h>
|
#include <AK/Traits.h>
|
||||||
|
@ -148,30 +149,50 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U = T>
|
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) {
|
if (!m_head) {
|
||||||
m_head = node;
|
m_head = node;
|
||||||
m_tail = node;
|
m_tail = node;
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
m_tail->next = node;
|
m_tail->next = node;
|
||||||
m_tail = node;
|
m_tail = node;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U = T>
|
||||||
|
ErrorOr<void> try_prepend(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 {};
|
||||||
|
}
|
||||||
|
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>
|
template<typename U = T>
|
||||||
void prepend(U&& value)
|
void prepend(U&& value)
|
||||||
{
|
{
|
||||||
auto* node = new Node(forward<U>(value));
|
MUST(try_prepend(forward<U>(value)));
|
||||||
if (!m_head) {
|
|
||||||
m_head = node;
|
|
||||||
m_tail = node;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
node->next = m_head;
|
|
||||||
m_head = node;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool contains_slow(const T& value) const
|
bool contains_slow(const T& value) const
|
||||||
{
|
{
|
||||||
|
@ -211,33 +232,51 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U = T>
|
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;
|
node->next = iterator.m_node;
|
||||||
if (m_head == iterator.m_node)
|
if (m_head == iterator.m_node)
|
||||||
m_head = node;
|
m_head = node;
|
||||||
if (iterator.m_prev)
|
if (iterator.m_prev)
|
||||||
iterator.m_prev->next = node;
|
iterator.m_prev->next = node;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
void insert_after(Iterator iterator, U&& value)
|
ErrorOr<void> try_insert_after(Iterator iterator, U&& value)
|
||||||
{
|
{
|
||||||
if (iterator.is_end()) {
|
if (iterator.is_end())
|
||||||
append(value);
|
return try_append(value);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
node->next = iterator.m_node->next;
|
||||||
|
|
||||||
iterator.m_node->next = node;
|
iterator.m_node->next = node;
|
||||||
|
|
||||||
if (m_tail == iterator.m_node)
|
if (m_tail == iterator.m_node)
|
||||||
m_tail = 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)
|
void remove(Iterator& iterator)
|
||||||
{
|
{
|
||||||
VERIFY(!iterator.is_end());
|
VERIFY(!iterator.is_end());
|
||||||
|
|
|
@ -59,12 +59,22 @@ public:
|
||||||
return List::take_first();
|
return List::take_first();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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>
|
template<typename U = T>
|
||||||
void append(U&& value)
|
void append(U&& value)
|
||||||
{
|
{
|
||||||
m_count++;
|
MUST(try_append(forward<T>(value)));
|
||||||
return List::append(forward<T>(value));
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool contains_slow(const T& value) const
|
bool contains_slow(const T& value) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -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.");
|
dbgln("IPv4Socket: did_receive unable to allocate storage for incoming packet.");
|
||||||
return false;
|
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);
|
set_can_read(true);
|
||||||
}
|
}
|
||||||
m_bytes_received += packet_size;
|
m_bytes_received += packet_size;
|
||||||
|
|
|
@ -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));
|
tcp_packet.set_checksum(compute_tcp_checksum(local_address(), peer_address(), tcp_packet, payload_size));
|
||||||
|
|
||||||
routing_decision.adapter->send_packet(packet->bytes());
|
bool expect_ack { tcp_packet.has_syn() || payload_size > 0 };
|
||||||
|
if (expect_ack) {
|
||||||
m_packets_out++;
|
bool append_failed { false };
|
||||||
m_bytes_out += buffer_size;
|
|
||||||
if (tcp_packet.has_syn() || payload_size > 0) {
|
|
||||||
m_unacked_packets.with_exclusive([&](auto& unacked_packets) {
|
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;
|
unacked_packets.size += payload_size;
|
||||||
enqueue_for_retransmit();
|
enqueue_for_retransmit();
|
||||||
});
|
});
|
||||||
} else {
|
if (append_failed)
|
||||||
routing_decision.adapter->release_packet_buffer(*packet);
|
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 {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue