2019-06-07 10:36:51 +03:00
# include <Kernel/FileSystem/FileDescription.h>
2019-04-02 20:54:38 +03:00
# include <Kernel/Net/IPv4Socket.h>
2019-06-07 12:43:58 +03:00
# include <Kernel/Net/LocalSocket.h>
# include <Kernel/Net/Socket.h>
2019-02-14 19:18:35 +03:00
# include <Kernel/Process.h>
2019-06-07 12:43:58 +03:00
# include <Kernel/UnixTypes.h>
2019-02-14 16:17:38 +03:00
# include <LibC/errno_numbers.h>
2019-06-21 19:37:47 +03:00
KResultOr < NonnullRefPtr < Socket > > Socket : : create ( int domain , int type , int protocol )
2019-02-14 16:17:38 +03:00
{
( void ) protocol ;
switch ( domain ) {
case AF_LOCAL :
2019-02-14 17:17:30 +03:00
return LocalSocket : : create ( type & SOCK_TYPE_MASK ) ;
2019-03-12 17:51:42 +03:00
case AF_INET :
return IPv4Socket : : create ( type & SOCK_TYPE_MASK , protocol ) ;
2019-02-14 16:17:38 +03:00
default :
2019-03-07 00:14:31 +03:00
return KResult ( - EAFNOSUPPORT ) ;
2019-02-14 16:17:38 +03:00
}
}
Socket : : Socket ( int domain , int type , int protocol )
2019-05-02 04:28:20 +03:00
: m_domain ( domain )
2019-02-14 16:17:38 +03:00
, m_type ( type )
, m_protocol ( protocol )
{
2019-02-14 19:18:35 +03:00
m_origin_pid = current - > pid ( ) ;
2019-02-14 16:17:38 +03:00
}
Socket : : ~ Socket ( )
{
}
2019-03-07 00:14:31 +03:00
KResult Socket : : listen ( int backlog )
2019-02-14 17:17:30 +03:00
{
LOCKER ( m_lock ) ;
2019-03-07 00:14:31 +03:00
if ( m_type ! = SOCK_STREAM )
return KResult ( - EOPNOTSUPP ) ;
2019-02-14 17:17:30 +03:00
m_backlog = backlog ;
2019-02-14 19:43:47 +03:00
kprintf ( " Socket{%p} listening with backlog=%d \n " , this , m_backlog ) ;
2019-03-07 00:14:31 +03:00
return KSuccess ;
2019-02-14 17:17:30 +03:00
}
2019-02-14 16:17:38 +03:00
2019-06-21 19:37:47 +03:00
RefPtr < Socket > Socket : : accept ( )
2019-02-14 17:17:30 +03:00
{
LOCKER ( m_lock ) ;
if ( m_pending . is_empty ( ) )
return nullptr ;
auto client = m_pending . take_first ( ) ;
2019-02-14 19:18:35 +03:00
ASSERT ( ! client - > is_connected ( ) ) ;
client - > m_connected = true ;
2019-02-14 17:17:30 +03:00
return client ;
}
2019-02-14 19:18:35 +03:00
2019-03-07 00:14:31 +03:00
KResult Socket : : queue_connection_from ( Socket & peer )
2019-02-14 19:18:35 +03:00
{
LOCKER ( m_lock ) ;
2019-03-07 00:14:31 +03:00
if ( m_pending . size ( ) > = m_backlog )
return KResult ( - ECONNREFUSED ) ;
2019-02-14 19:18:35 +03:00
m_pending . append ( peer ) ;
2019-03-07 00:14:31 +03:00
return KSuccess ;
2019-02-14 19:18:35 +03:00
}
2019-03-13 15:13:23 +03:00
KResult Socket : : setsockopt ( int level , int option , const void * value , socklen_t value_size )
{
ASSERT ( level = = SOL_SOCKET ) ;
switch ( option ) {
case SO_SNDTIMEO :
if ( value_size ! = sizeof ( timeval ) )
return KResult ( - EINVAL ) ;
2019-03-14 14:20:38 +03:00
m_send_timeout = * ( const timeval * ) value ;
2019-03-13 15:13:23 +03:00
return KSuccess ;
case SO_RCVTIMEO :
if ( value_size ! = sizeof ( timeval ) )
return KResult ( - EINVAL ) ;
2019-03-14 14:20:38 +03:00
m_receive_timeout = * ( const timeval * ) value ;
2019-03-13 15:13:23 +03:00
return KSuccess ;
default :
2019-05-20 20:45:27 +03:00
kprintf ( " %s(%u): setsockopt() at SOL_SOCKET with unimplemented option %d \n " , current - > process ( ) . name ( ) . characters ( ) , current - > process ( ) . pid ( ) , option ) ;
2019-03-13 15:13:23 +03:00
return KResult ( - ENOPROTOOPT ) ;
}
}
KResult Socket : : getsockopt ( int level , int option , void * value , socklen_t * value_size )
{
ASSERT ( level = = SOL_SOCKET ) ;
switch ( option ) {
case SO_SNDTIMEO :
if ( * value_size < sizeof ( timeval ) )
return KResult ( - EINVAL ) ;
* ( timeval * ) value = m_send_timeout ;
* value_size = sizeof ( timeval ) ;
return KSuccess ;
case SO_RCVTIMEO :
if ( * value_size < sizeof ( timeval ) )
return KResult ( - EINVAL ) ;
* ( timeval * ) value = m_receive_timeout ;
* value_size = sizeof ( timeval ) ;
return KSuccess ;
2019-05-29 22:59:50 +03:00
case SO_ERROR :
if ( * value_size < sizeof ( int ) )
return KResult ( - EINVAL ) ;
kprintf ( " %s(%u): getsockopt() SO_ERROR: WARNING! I have no idea what the real error is, so I'll just stick my fingers in my ears and pretend there is none! %d \n " , current - > process ( ) . name ( ) . characters ( ) , option ) ;
* ( int * ) value = 0 ;
* value_size = sizeof ( int ) ;
return KSuccess ;
2019-03-13 15:13:23 +03:00
default :
2019-05-29 22:59:50 +03:00
kprintf ( " %s(%u): getsockopt() at SOL_SOCKET with unimplemented option %d \n " , current - > process ( ) . name ( ) . characters ( ) , option ) ;
2019-03-13 15:13:23 +03:00
return KResult ( - ENOPROTOOPT ) ;
}
}
void Socket : : load_receive_deadline ( )
{
kgettimeofday ( m_receive_deadline ) ;
m_receive_deadline . tv_sec + = m_receive_timeout . tv_sec ;
m_receive_deadline . tv_usec + = m_receive_timeout . tv_usec ;
m_receive_deadline . tv_sec + = ( m_send_timeout . tv_usec / 1000000 ) * 1 ;
m_receive_deadline . tv_usec % = 1000000 ;
}
void Socket : : load_send_deadline ( )
{
kgettimeofday ( m_send_deadline ) ;
m_send_deadline . tv_sec + = m_send_timeout . tv_sec ;
m_send_deadline . tv_usec + = m_send_timeout . tv_usec ;
m_send_deadline . tv_sec + = ( m_send_timeout . tv_usec / 1000000 ) * 1 ;
m_send_deadline . tv_usec % = 1000000 ;
}
2019-05-03 21:42:43 +03:00
static const char * to_string ( SocketRole role )
{
switch ( role ) {
case SocketRole : : Listener :
return " Listener " ;
case SocketRole : : Accepted :
return " Accepted " ;
case SocketRole : : Connected :
return " Connected " ;
default :
return " None " ;
}
}
2019-06-13 23:03:04 +03:00
String Socket : : absolute_path ( const FileDescription & description ) const
2019-05-03 21:42:43 +03:00
{
2019-06-13 23:03:04 +03:00
return String : : format ( " socket:%x (role: %s) " , this , to_string ( description . socket_role ( ) ) ) ;
2019-05-03 21:42:43 +03:00
}
2019-08-05 11:03:19 +03:00
ssize_t Socket : : read ( FileDescription & description , u8 * buffer , ssize_t size )
{
return recvfrom ( description , buffer , size , 0 , nullptr , 0 ) ;
}
ssize_t Socket : : write ( FileDescription & description , const u8 * data , ssize_t size )
{
return sendto ( description , data , size , 0 , nullptr , 0 ) ;
}