mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 07:02:44 +00: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); | ||||||
| 
 | 
 | ||||||
|  |     if (!m_no_delay) { | ||||||
|         // RFC 896 (Nagle’s algorithm): https://www.ietf.org/rfc/rfc0896
 |         // RFC 896 (Nagle’s algorithm): https://www.ietf.org/rfc/rfc0896
 | ||||||
|         // "The solution is to inhibit the sending of new TCP  segments when
 |         // "The solution is to inhibit the sending of new TCP  segments when
 | ||||||
|         //  new  outgoing  data  arrives  from  the  user  if  any previously
 |         //  new  outgoing  data  arrives  from  the  user  if  any previously
 | ||||||
|         //  transmitted data on the connection remains unacknowledged.   This
 |         //  transmitted data on the connection remains unacknowledged.   This
 | ||||||
|         //  inhibition  is  to be unconditional; no timers, tests for size of
 |         //  inhibition  is  to be unconditional; no timers, tests for size of
 | ||||||
|         //  data received, or other conditions are required."
 |         //  data received, or other conditions are required."
 | ||||||
|     // FIXME: Make this configurable via TCP_NODELAY.
 |  | ||||||
|         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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Romain Chardiny
						Romain Chardiny