2020-01-18 11:38:21 +03:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2019-04-03 13:36:40 +03:00
# include <Kernel/Devices/RandomDevice.h>
2019-06-07 12:43:58 +03:00
# include <Kernel/Net/NetworkAdapter.h>
2019-04-02 16:46:44 +03:00
# include <Kernel/Net/Routing.h>
2019-06-07 12:43:58 +03:00
# include <Kernel/Net/UDP.h>
# include <Kernel/Net/UDPSocket.h>
# include <Kernel/Process.h>
2020-01-03 14:36:30 +03:00
# include <Kernel/Random.h>
2019-03-14 14:43:18 +03:00
2020-02-16 03:27:42 +03:00
namespace Kernel {
2019-08-09 13:27:40 +03:00
void UDPSocket : : for_each ( Function < void ( UDPSocket & ) > callback )
{
LOCKER ( sockets_by_port ( ) . lock ( ) ) ;
for ( auto it : sockets_by_port ( ) . resource ( ) )
callback ( * it . value ) ;
}
2019-07-03 22:17:35 +03:00
Lockable < HashMap < u16 , UDPSocket * > > & UDPSocket : : sockets_by_port ( )
2019-03-14 14:43:18 +03:00
{
2019-07-03 22:17:35 +03:00
static Lockable < HashMap < u16 , UDPSocket * > > * s_map ;
2019-03-14 14:43:18 +03:00
if ( ! s_map )
2019-07-03 22:17:35 +03:00
s_map = new Lockable < HashMap < u16 , UDPSocket * > > ;
2019-03-14 14:43:18 +03:00
return * s_map ;
}
2019-08-09 10:16:12 +03:00
SocketHandle < UDPSocket > UDPSocket : : from_port ( u16 port )
2019-03-14 14:43:18 +03:00
{
2019-06-21 19:37:47 +03:00
RefPtr < UDPSocket > socket ;
2019-03-14 14:43:18 +03:00
{
LOCKER ( sockets_by_port ( ) . lock ( ) ) ;
auto it = sockets_by_port ( ) . resource ( ) . find ( port ) ;
if ( it = = sockets_by_port ( ) . resource ( ) . end ( ) )
2019-06-07 12:43:58 +03:00
return { } ;
2019-03-14 14:43:18 +03:00
socket = ( * it ) . value ;
ASSERT ( socket ) ;
}
2019-08-09 10:16:12 +03:00
return { * socket } ;
2019-03-14 14:43:18 +03:00
}
UDPSocket : : UDPSocket ( int protocol )
: IPv4Socket ( SOCK_DGRAM , protocol )
{
}
UDPSocket : : ~ UDPSocket ( )
{
LOCKER ( sockets_by_port ( ) . lock ( ) ) ;
2019-05-04 17:40:34 +03:00
sockets_by_port ( ) . resource ( ) . remove ( local_port ( ) ) ;
2019-03-14 14:43:18 +03:00
}
2019-06-21 19:37:47 +03:00
NonnullRefPtr < UDPSocket > UDPSocket : : create ( int protocol )
2019-03-14 14:43:18 +03:00
{
return adopt ( * new UDPSocket ( protocol ) ) ;
}
2019-08-04 22:07:50 +03:00
int UDPSocket : : protocol_receive ( const KBuffer & packet_buffer , void * buffer , size_t buffer_size , int flags )
2019-03-14 14:43:18 +03:00
{
( void ) flags ;
2019-08-04 22:07:50 +03:00
auto & ipv4_packet = * ( const IPv4Packet * ) ( packet_buffer . data ( ) ) ;
2019-03-14 14:43:18 +03:00
auto & udp_packet = * static_cast < const UDPPacket * > ( ipv4_packet . payload ( ) ) ;
ASSERT ( udp_packet . length ( ) > = sizeof ( UDPPacket ) ) ; // FIXME: This should be rejected earlier.
ASSERT ( buffer_size > = ( udp_packet . length ( ) - sizeof ( UDPPacket ) ) ) ;
memcpy ( buffer , udp_packet . payload ( ) , udp_packet . length ( ) - sizeof ( UDPPacket ) ) ;
return udp_packet . length ( ) - sizeof ( UDPPacket ) ;
}
2020-01-29 14:27:42 +03:00
int UDPSocket : : protocol_send ( const void * data , size_t data_length )
2019-03-14 14:43:18 +03:00
{
2020-04-04 23:46:45 +03:00
auto routing_decision = route_to ( peer_address ( ) , local_address ( ) , bound_interface ( ) ) ;
2019-08-29 04:18:38 +03:00
if ( routing_decision . is_zero ( ) )
2019-04-02 16:46:44 +03:00
return - EHOSTUNREACH ;
2019-03-14 14:43:18 +03:00
auto buffer = ByteBuffer : : create_zeroed ( sizeof ( UDPPacket ) + data_length ) ;
2019-09-30 09:57:01 +03:00
auto & udp_packet = * ( UDPPacket * ) ( buffer . data ( ) ) ;
2019-05-04 17:40:34 +03:00
udp_packet . set_source_port ( local_port ( ) ) ;
udp_packet . set_destination_port ( peer_port ( ) ) ;
2019-03-14 14:43:18 +03:00
udp_packet . set_length ( sizeof ( UDPPacket ) + data_length ) ;
memcpy ( udp_packet . payload ( ) , data , data_length ) ;
2020-03-01 22:45:39 +03:00
klog ( ) < < " sending as udp packet from " < < routing_decision . adapter - > ipv4_address ( ) . to_string ( ) . characters ( ) < < " : " < < local_port ( ) < < " to " < < peer_address ( ) . to_string ( ) . characters ( ) < < " : " < < peer_port ( ) < < " ! " ;
2019-09-19 22:40:06 +03:00
routing_decision . adapter - > send_ipv4 ( routing_decision . next_hop , peer_address ( ) , IPv4Protocol : : UDP , buffer . data ( ) , buffer . size ( ) , ttl ( ) ) ;
2019-03-14 14:43:18 +03:00
return data_length ;
}
2019-08-11 16:38:20 +03:00
KResult UDPSocket : : protocol_connect ( FileDescription & , ShouldBlock )
{
m_role = Role : : Connected ;
2020-01-26 16:43:08 +03:00
set_connected ( true ) ;
2019-08-11 16:38:20 +03:00
return KSuccess ;
}
2019-05-04 17:40:34 +03:00
int UDPSocket : : protocol_allocate_local_port ( )
2019-03-14 14:43:18 +03:00
{
2019-07-03 22:17:35 +03:00
static const u16 first_ephemeral_port = 32768 ;
static const u16 last_ephemeral_port = 60999 ;
static const u16 ephemeral_port_range_size = last_ephemeral_port - first_ephemeral_port ;
2020-01-03 14:36:30 +03:00
u16 first_scan_port = first_ephemeral_port + get_good_random < u16 > ( ) % ephemeral_port_range_size ;
2019-03-18 06:03:44 +03:00
2019-03-14 14:43:18 +03:00
LOCKER ( sockets_by_port ( ) . lock ( ) ) ;
2019-07-03 22:17:35 +03:00
for ( u16 port = first_scan_port ; ; ) {
2019-03-14 14:43:18 +03:00
auto it = sockets_by_port ( ) . resource ( ) . find ( port ) ;
if ( it = = sockets_by_port ( ) . resource ( ) . end ( ) ) {
2019-05-04 17:40:34 +03:00
set_local_port ( port ) ;
2019-03-14 14:43:18 +03:00
sockets_by_port ( ) . resource ( ) . set ( port , this ) ;
2019-03-18 06:03:44 +03:00
return port ;
2019-03-14 14:43:18 +03:00
}
2019-03-18 06:03:44 +03:00
+ + port ;
if ( port > last_ephemeral_port )
port = first_ephemeral_port ;
if ( port = = first_scan_port )
break ;
2019-03-14 14:43:18 +03:00
}
2019-03-18 06:03:44 +03:00
return - EADDRINUSE ;
2019-03-14 14:43:18 +03:00
}
2019-05-03 22:51:40 +03:00
KResult UDPSocket : : protocol_bind ( )
{
LOCKER ( sockets_by_port ( ) . lock ( ) ) ;
2019-05-04 17:40:34 +03:00
if ( sockets_by_port ( ) . resource ( ) . contains ( local_port ( ) ) )
2019-05-03 22:51:40 +03:00
return KResult ( - EADDRINUSE ) ;
2019-05-04 17:40:34 +03:00
sockets_by_port ( ) . resource ( ) . set ( local_port ( ) , this ) ;
2019-05-03 22:51:40 +03:00
return KSuccess ;
}
2020-02-16 03:27:42 +03:00
}