mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-22 17:31:58 -05:00
Kernel/Net: Implement TCP_NODELAY
This commit is contained in:
parent
38a368c8f6
commit
61ac554a34
5 changed files with 84 additions and 12 deletions
18
Kernel/API/POSIX/netinet/tcp.h
Normal file
18
Kernel/API/POSIX/netinet/tcp.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Romain Chardiny <romain.chardiny@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TCP_NODELAY 10
|
||||||
|
#define TCP_MAXSEG 11
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -211,16 +211,17 @@ ErrorOr<size_t> TCPSocket::protocol_send(UserOrKernelBuffer const& data, size_t
|
||||||
return set_so_error(EHOSTUNREACH);
|
return set_so_error(EHOSTUNREACH);
|
||||||
size_t mss = routing_decision.adapter->mtu() - sizeof(IPv4Packet) - sizeof(TCPPacket);
|
size_t mss = routing_decision.adapter->mtu() - sizeof(IPv4Packet) - sizeof(TCPPacket);
|
||||||
|
|
||||||
// RFC 896 (Nagle’s algorithm): https://www.ietf.org/rfc/rfc0896
|
if (!m_no_delay) {
|
||||||
// "The solution is to inhibit the sending of new TCP segments when
|
// RFC 896 (Nagle’s algorithm): https://www.ietf.org/rfc/rfc0896
|
||||||
// new outgoing data arrives from the user if any previously
|
// "The solution is to inhibit the sending of new TCP segments when
|
||||||
// transmitted data on the connection remains unacknowledged. This
|
// new outgoing data arrives from the user if any previously
|
||||||
// inhibition is to be unconditional; no timers, tests for size of
|
// transmitted data on the connection remains unacknowledged. This
|
||||||
// data received, or other conditions are required."
|
// inhibition is to be unconditional; no timers, tests for size of
|
||||||
// FIXME: Make this configurable via TCP_NODELAY.
|
// data received, or other conditions are required."
|
||||||
auto has_unacked_data = m_unacked_packets.with_shared([&](auto const& packets) { return packets.size > 0; });
|
auto has_unacked_data = m_unacked_packets.with_shared([&](auto const& packets) { return packets.size > 0; });
|
||||||
if (has_unacked_data && data_length < mss)
|
if (has_unacked_data && data_length < mss)
|
||||||
return set_so_error(EAGAIN);
|
return set_so_error(EAGAIN);
|
||||||
|
}
|
||||||
|
|
||||||
data_length = min(data_length, mss);
|
data_length = min(data_length, mss);
|
||||||
TRY(send_tcp_packet(TCPFlags::PSH | TCPFlags::ACK, &data, data_length, &routing_decision));
|
TRY(send_tcp_packet(TCPFlags::PSH | TCPFlags::ACK, &data, data_length, &routing_decision));
|
||||||
|
@ -427,6 +428,54 @@ NetworkOrdered<u16> TCPSocket::compute_tcp_checksum(IPv4Address const& source, I
|
||||||
return ~(checksum & 0xffff);
|
return ~(checksum & 0xffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> TCPSocket::setsockopt(int level, int option, Userspace<void const*> user_value, socklen_t user_value_size)
|
||||||
|
{
|
||||||
|
if (level != IPPROTO_TCP)
|
||||||
|
return IPv4Socket::setsockopt(level, option, user_value, user_value_size);
|
||||||
|
|
||||||
|
MutexLocker locker(mutex());
|
||||||
|
|
||||||
|
switch (option) {
|
||||||
|
case TCP_NODELAY:
|
||||||
|
if (user_value_size < sizeof(int))
|
||||||
|
return EINVAL;
|
||||||
|
int value;
|
||||||
|
TRY(copy_from_user(&value, static_ptr_cast<int const*>(user_value)));
|
||||||
|
if (value != 0 && value != 1)
|
||||||
|
return EINVAL;
|
||||||
|
m_no_delay = value;
|
||||||
|
return {};
|
||||||
|
default:
|
||||||
|
dbgln("setsockopt({}) at IPPROTO_TCP not implemented.", option);
|
||||||
|
return ENOPROTOOPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> TCPSocket::getsockopt(OpenFileDescription& description, int level, int option, Userspace<void*> value, Userspace<socklen_t*> value_size)
|
||||||
|
{
|
||||||
|
if (level != IPPROTO_TCP)
|
||||||
|
return IPv4Socket::getsockopt(description, level, option, value, value_size);
|
||||||
|
|
||||||
|
MutexLocker locker(mutex());
|
||||||
|
|
||||||
|
socklen_t size;
|
||||||
|
TRY(copy_from_user(&size, value_size.unsafe_userspace_ptr()));
|
||||||
|
|
||||||
|
switch (option) {
|
||||||
|
case TCP_NODELAY: {
|
||||||
|
int nodelay = m_no_delay ? 1 : 0;
|
||||||
|
if (size < sizeof(nodelay))
|
||||||
|
return EINVAL;
|
||||||
|
TRY(copy_to_user(static_ptr_cast<int*>(value), &nodelay));
|
||||||
|
size = sizeof(nodelay);
|
||||||
|
return copy_to_user(value_size, &size);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
dbgln("getsockopt({}) at IPPROTO_TCP not implemented.", option);
|
||||||
|
return ENOPROTOOPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<void> TCPSocket::protocol_bind()
|
ErrorOr<void> TCPSocket::protocol_bind()
|
||||||
{
|
{
|
||||||
dbgln_if(TCP_SOCKET_DEBUG, "TCPSocket::protocol_bind(), local_port() is {}", local_port());
|
dbgln_if(TCP_SOCKET_DEBUG, "TCPSocket::protocol_bind(), local_port() is {}", local_port());
|
||||||
|
|
|
@ -165,6 +165,9 @@ public:
|
||||||
|
|
||||||
static NetworkOrdered<u16> compute_tcp_checksum(IPv4Address const& source, IPv4Address const& destination, TCPPacket const&, u16 payload_size);
|
static NetworkOrdered<u16> compute_tcp_checksum(IPv4Address const& source, IPv4Address const& destination, TCPPacket const&, u16 payload_size);
|
||||||
|
|
||||||
|
virtual ErrorOr<void> setsockopt(int level, int option, Userspace<void const*>, socklen_t) override;
|
||||||
|
virtual ErrorOr<void> getsockopt(OpenFileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void set_direction(Direction direction) { m_direction = direction; }
|
void set_direction(Direction direction) { m_direction = direction; }
|
||||||
|
|
||||||
|
@ -227,6 +230,8 @@ private:
|
||||||
// peer's advertised window size.
|
// peer's advertised window size.
|
||||||
u32 m_send_window_size { 64 * KiB };
|
u32 m_send_window_size { 64 * KiB };
|
||||||
|
|
||||||
|
bool m_no_delay { false };
|
||||||
|
|
||||||
IntrusiveListNode<TCPSocket> m_retransmit_list_node;
|
IntrusiveListNode<TCPSocket> m_retransmit_list_node;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <Kernel/API/POSIX/net/if_arp.h>
|
#include <Kernel/API/POSIX/net/if_arp.h>
|
||||||
#include <Kernel/API/POSIX/net/route.h>
|
#include <Kernel/API/POSIX/net/route.h>
|
||||||
#include <Kernel/API/POSIX/netinet/in.h>
|
#include <Kernel/API/POSIX/netinet/in.h>
|
||||||
|
#include <Kernel/API/POSIX/netinet/tcp.h>
|
||||||
#include <Kernel/API/POSIX/poll.h>
|
#include <Kernel/API/POSIX/poll.h>
|
||||||
#include <Kernel/API/POSIX/sched.h>
|
#include <Kernel/API/POSIX/sched.h>
|
||||||
#include <Kernel/API/POSIX/serenity.h>
|
#include <Kernel/API/POSIX/serenity.h>
|
||||||
|
|
|
@ -6,5 +6,4 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define TCP_NODELAY 10
|
#include <Kernel/API/POSIX/netinet/tcp.h>
|
||||||
#define TCP_MAXSEG 11
|
|
||||||
|
|
Loading…
Reference in a new issue