2020-01-18 09:38:21 +01: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-08-10 19:10:36 +03:00
# include <AK/StringBuilder.h>
2019-06-07 09:36:51 +02:00
# include <Kernel/FileSystem/FileDescription.h>
2019-04-02 19:54:38 +02:00
# include <Kernel/Net/IPv4Socket.h>
2019-06-07 11:43:58 +02:00
# include <Kernel/Net/LocalSocket.h>
# include <Kernel/Net/Socket.h>
2019-02-14 17:18:35 +01:00
# include <Kernel/Process.h>
2019-06-07 11:43:58 +02:00
# include <Kernel/UnixTypes.h>
2019-02-14 14:17:38 +01:00
# include <LibC/errno_numbers.h>
2019-08-10 13:17:00 +10:00
//#define SOCKET_DEBUG
2019-06-21 18:37:47 +02:00
KResultOr < NonnullRefPtr < Socket > > Socket : : create ( int domain , int type , int protocol )
2019-02-14 14:17:38 +01:00
{
switch ( domain ) {
case AF_LOCAL :
2019-02-14 15:17:30 +01:00
return LocalSocket : : create ( type & SOCK_TYPE_MASK ) ;
2019-03-12 15:51:42 +01:00
case AF_INET :
return IPv4Socket : : create ( type & SOCK_TYPE_MASK , protocol ) ;
2019-02-14 14:17:38 +01:00
default :
2019-03-06 22:14:31 +01:00
return KResult ( - EAFNOSUPPORT ) ;
2019-02-14 14:17:38 +01:00
}
}
Socket : : Socket ( int domain , int type , int protocol )
2019-05-02 03:28:20 +02:00
: m_domain ( domain )
2019-02-14 14:17:38 +01:00
, m_type ( type )
, m_protocol ( protocol )
{
2019-12-06 18:38:36 +01:00
auto & process = current - > process ( ) ;
m_origin = { process . pid ( ) , process . uid ( ) , process . gid ( ) } ;
2019-02-14 14:17:38 +01:00
}
Socket : : ~ Socket ( )
{
}
2019-08-10 13:17:00 +10:00
void Socket : : set_setup_state ( SetupState new_setup_state )
{
# ifdef SOCKET_DEBUG
kprintf ( " %s(%u) Socket{%p} setup state moving from %s to %s \n " , current - > process ( ) . name ( ) . characters ( ) , current - > pid ( ) , this , to_string ( m_setup_state ) , to_string ( new_setup_state ) ) ;
# endif
m_setup_state = new_setup_state ;
}
2019-06-21 18:37:47 +02:00
RefPtr < Socket > Socket : : accept ( )
2019-02-14 15:17:30 +01:00
{
LOCKER ( m_lock ) ;
if ( m_pending . is_empty ( ) )
return nullptr ;
2019-08-10 13:17:00 +10:00
# ifdef SOCKET_DEBUG
kprintf ( " %s(%u) Socket{%p} de-queueing connection \n " , current - > process ( ) . name ( ) . characters ( ) , current - > pid ( ) , this ) ;
# endif
2019-02-14 15:17:30 +01:00
auto client = m_pending . take_first ( ) ;
2019-02-14 17:18:35 +01:00
ASSERT ( ! client - > is_connected ( ) ) ;
2019-12-06 18:38:36 +01:00
auto & process = current - > process ( ) ;
client - > m_acceptor = { process . pid ( ) , process . uid ( ) , process . gid ( ) } ;
2019-02-14 17:18:35 +01:00
client - > m_connected = true ;
2019-08-11 16:38:20 +03:00
client - > m_role = Role : : Accepted ;
2019-02-14 15:17:30 +01:00
return client ;
}
2019-02-14 17:18:35 +01:00
2019-08-09 12:41:06 +10:00
KResult Socket : : queue_connection_from ( NonnullRefPtr < Socket > peer )
2019-02-14 17:18:35 +01:00
{
2019-08-10 13:17:00 +10:00
# ifdef SOCKET_DEBUG
kprintf ( " %s(%u) Socket{%p} queueing connection \n " , current - > process ( ) . name ( ) . characters ( ) , current - > pid ( ) , this ) ;
# endif
2019-02-14 17:18:35 +01:00
LOCKER ( m_lock ) ;
2019-03-06 22:14:31 +01:00
if ( m_pending . size ( ) > = m_backlog )
return KResult ( - ECONNREFUSED ) ;
2019-02-14 17:18:35 +01:00
m_pending . append ( peer ) ;
2019-03-06 22:14:31 +01:00
return KSuccess ;
2019-02-14 17:18:35 +01:00
}
2019-03-13 13:13:23 +01: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 12:20:38 +01:00
m_send_timeout = * ( const timeval * ) value ;
2019-03-13 13:13:23 +01:00
return KSuccess ;
case SO_RCVTIMEO :
if ( value_size ! = sizeof ( timeval ) )
return KResult ( - EINVAL ) ;
2019-03-14 12:20:38 +01:00
m_receive_timeout = * ( const timeval * ) value ;
2019-03-13 13:13:23 +01:00
return KSuccess ;
default :
2020-02-07 23:48:12 +01:00
dbg ( ) < < " setsockopt( " < < option < < " ) at SOL_SOCKET not implemented. " ;
2019-03-13 13:13:23 +01:00
return KResult ( - ENOPROTOOPT ) ;
}
}
2019-12-06 18:38:36 +01:00
KResult Socket : : getsockopt ( FileDescription & , int level , int option , void * value , socklen_t * value_size )
2019-03-13 13:13:23 +01:00
{
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 21:59:50 +02:00
case SO_ERROR :
if ( * value_size < sizeof ( int ) )
return KResult ( - EINVAL ) ;
2020-02-07 23:48:12 +01:00
dbg ( ) < < " getsockopt(SO_ERROR): FIXME! " ;
2019-05-29 21:59:50 +02:00
* ( int * ) value = 0 ;
* value_size = sizeof ( int ) ;
return KSuccess ;
2019-03-13 13:13:23 +01:00
default :
2020-02-07 23:48:12 +01:00
dbg ( ) < < " getsockopt( " < < option < < " ) at SOL_SOCKET not implemented. " ;
2019-03-13 13:13:23 +01:00
return KResult ( - ENOPROTOOPT ) ;
}
}
2019-08-05 10:03:19 +02:00
ssize_t Socket : : read ( FileDescription & description , u8 * buffer , ssize_t size )
{
2020-02-08 00:52:33 +01:00
if ( is_shut_down_for_reading ( ) )
return 0 ;
2019-08-05 10:03:19 +02:00
return recvfrom ( description , buffer , size , 0 , nullptr , 0 ) ;
}
ssize_t Socket : : write ( FileDescription & description , const u8 * data , ssize_t size )
{
2020-02-08 00:52:33 +01:00
if ( is_shut_down_for_writing ( ) )
return - EPIPE ;
2019-08-05 10:03:19 +02:00
return sendto ( description , data , size , 0 , nullptr , 0 ) ;
}
2020-02-08 00:52:33 +01:00
KResult Socket : : shutdown ( int how )
{
if ( type ( ) = = SOCK_STREAM & & ! is_connected ( ) )
return KResult ( - ENOTCONN ) ;
m_shut_down_for_reading | = how & SHUT_RD ;
m_shut_down_for_writing | = how & SHUT_WR ;
return KSuccess ;
}