2019-08-10 18:58:06 +03:00
# include <AK/StringBuilder.h>
2019-06-07 09:36:51 +02:00
# include <Kernel/FileSystem/FileDescription.h>
2019-04-03 12:25:24 +02:00
# include <Kernel/FileSystem/VirtualFileSystem.h>
2019-06-07 11:43:58 +02:00
# include <Kernel/Net/LocalSocket.h>
# include <Kernel/Process.h>
# include <Kernel/UnixTypes.h>
2019-02-14 14:38:30 +01:00
# include <LibC/errno_numbers.h>
2019-02-14 14:17:38 +01:00
2019-03-01 10:51:58 +01:00
//#define DEBUG_LOCAL_SOCKET
2019-08-10 18:58:06 +03:00
Lockable < InlineLinkedList < LocalSocket > > & LocalSocket : : all_sockets ( )
{
static Lockable < InlineLinkedList < LocalSocket > > * s_list ;
if ( ! s_list )
s_list = new Lockable < InlineLinkedList < LocalSocket > > ( ) ;
return * s_list ;
}
void LocalSocket : : for_each ( Function < void ( LocalSocket & ) > callback )
{
LOCKER ( all_sockets ( ) . lock ( ) ) ;
for ( auto & socket : all_sockets ( ) . resource ( ) )
callback ( socket ) ;
}
2019-06-21 18:37:47 +02:00
NonnullRefPtr < LocalSocket > LocalSocket : : create ( int type )
2019-02-14 14:17:38 +01:00
{
return adopt ( * new LocalSocket ( type ) ) ;
}
LocalSocket : : LocalSocket ( int type )
: Socket ( AF_LOCAL , type , 0 )
{
2019-08-10 18:58:06 +03:00
LOCKER ( all_sockets ( ) . lock ( ) ) ;
all_sockets ( ) . resource ( ) . append ( this ) ;
2019-03-01 10:51:58 +01:00
# ifdef DEBUG_LOCAL_SOCKET
2019-03-23 22:03:17 +01:00
kprintf ( " %s(%u) LocalSocket{%p} created with type=%u \n " , current - > process ( ) . name ( ) . characters ( ) , current - > pid ( ) , this , type ) ;
2019-03-01 10:51:58 +01:00
# endif
2019-02-14 14:17:38 +01:00
}
LocalSocket : : ~ LocalSocket ( )
{
2019-08-10 18:58:06 +03:00
LOCKER ( all_sockets ( ) . lock ( ) ) ;
all_sockets ( ) . resource ( ) . remove ( this ) ;
2019-02-14 14:17:38 +01:00
}
2019-05-20 20:33:03 +02:00
bool LocalSocket : : get_local_address ( sockaddr * address , socklen_t * address_size )
2019-02-14 15:17:30 +01:00
{
// FIXME: Look into what fallback behavior we should have here.
if ( * address_size ! = sizeof ( sockaddr_un ) )
return false ;
memcpy ( address , & m_address , sizeof ( sockaddr_un ) ) ;
* address_size = sizeof ( sockaddr_un ) ;
return true ;
}
2019-05-20 20:33:03 +02:00
bool LocalSocket : : get_peer_address ( sockaddr * address , socklen_t * address_size )
{
return get_local_address ( address , address_size ) ;
}
2019-03-06 22:14:31 +01:00
KResult LocalSocket : : bind ( const sockaddr * address , socklen_t address_size )
2019-02-14 14:38:30 +01:00
{
2019-08-10 13:17:00 +10:00
ASSERT ( setup_state ( ) = = SetupState : : Unstarted ) ;
2019-03-06 22:14:31 +01:00
if ( address_size ! = sizeof ( sockaddr_un ) )
return KResult ( - EINVAL ) ;
if ( address - > sa_family ! = AF_LOCAL )
return KResult ( - EINVAL ) ;
2019-02-14 14:38:30 +01:00
const sockaddr_un & local_address = * reinterpret_cast < const sockaddr_un * > ( address ) ;
2019-08-10 18:49:14 +03:00
char safe_address [ sizeof ( local_address . sun_path ) + 1 ] = { 0 } ;
2019-02-14 14:38:30 +01:00
memcpy ( safe_address , local_address . sun_path , sizeof ( local_address . sun_path ) ) ;
2019-03-01 10:51:58 +01:00
# ifdef DEBUG_LOCAL_SOCKET
2019-03-23 22:03:17 +01:00
kprintf ( " %s(%u) LocalSocket{%p} bind(%s) \n " , current - > process ( ) . name ( ) . characters ( ) , current - > pid ( ) , this , safe_address ) ;
2019-03-01 10:51:58 +01:00
# endif
2019-02-14 14:38:30 +01:00
2019-05-30 20:23:50 +02:00
auto result = VFS : : the ( ) . open ( safe_address , O_CREAT | O_EXCL , S_IFSOCK | 0666 , current - > process ( ) . current_directory ( ) ) ;
2019-03-06 22:14:31 +01:00
if ( result . is_error ( ) ) {
if ( result . error ( ) = = - EEXIST )
return KResult ( - EADDRINUSE ) ;
return result . error ( ) ;
2019-02-14 14:38:30 +01:00
}
2019-03-06 22:14:31 +01:00
m_file = move ( result . value ( ) ) ;
2019-02-14 15:17:30 +01:00
2019-02-14 15:55:19 +01:00
ASSERT ( m_file - > inode ( ) ) ;
m_file - > inode ( ) - > bind_socket ( * this ) ;
2019-02-14 15:17:30 +01:00
m_address = local_address ;
m_bound = true ;
2019-03-06 22:14:31 +01:00
return KSuccess ;
2019-02-14 14:38:30 +01:00
}
2019-02-14 15:55:19 +01:00
2019-06-13 22:03:04 +02:00
KResult LocalSocket : : connect ( FileDescription & description , const sockaddr * address , socklen_t address_size , ShouldBlock )
2019-02-14 15:55:19 +01:00
{
ASSERT ( ! m_bound ) ;
2019-03-06 22:14:31 +01:00
if ( address_size ! = sizeof ( sockaddr_un ) )
return KResult ( - EINVAL ) ;
if ( address - > sa_family ! = AF_LOCAL )
return KResult ( - EINVAL ) ;
2019-02-14 15:55:19 +01:00
const sockaddr_un & local_address = * reinterpret_cast < const sockaddr_un * > ( address ) ;
2019-08-10 18:49:14 +03:00
char safe_address [ sizeof ( local_address . sun_path ) + 1 ] = { 0 } ;
2019-02-14 15:55:19 +01:00
memcpy ( safe_address , local_address . sun_path , sizeof ( local_address . sun_path ) ) ;
2019-03-01 10:51:58 +01:00
# ifdef DEBUG_LOCAL_SOCKET
2019-03-23 22:03:17 +01:00
kprintf ( " %s(%u) LocalSocket{%p} connect(%s) \n " , current - > process ( ) . name ( ) . characters ( ) , current - > pid ( ) , this , safe_address ) ;
2019-03-01 10:51:58 +01:00
# endif
2019-02-14 15:55:19 +01:00
2019-06-13 22:03:04 +02:00
auto description_or_error = VFS : : the ( ) . open ( safe_address , 0 , 0 , current - > process ( ) . current_directory ( ) ) ;
if ( description_or_error . is_error ( ) )
2019-03-06 22:14:31 +01:00
return KResult ( - ECONNREFUSED ) ;
2019-08-10 18:58:06 +03:00
2019-06-13 22:03:04 +02:00
m_file = move ( description_or_error . value ( ) ) ;
2019-03-06 22:14:31 +01:00
2019-02-14 15:55:19 +01:00
ASSERT ( m_file - > inode ( ) ) ;
2019-03-06 22:14:31 +01:00
if ( ! m_file - > inode ( ) - > socket ( ) )
return KResult ( - ECONNREFUSED ) ;
2019-02-14 15:55:19 +01:00
m_address = local_address ;
2019-02-14 17:18:35 +01:00
2019-08-11 16:38:20 +03:00
ASSERT ( m_connect_side_fd = = & description ) ;
m_connect_side_role = Role : : Connecting ;
2019-02-14 17:18:35 +01:00
auto peer = m_file - > inode ( ) - > socket ( ) ;
2019-03-06 22:14:31 +01:00
auto result = peer - > queue_connection_from ( * this ) ;
2019-08-11 16:38:20 +03:00
if ( result . is_error ( ) ) {
m_connect_side_role = Role : : None ;
2019-03-06 22:14:31 +01:00
return result ;
2019-08-11 16:38:20 +03:00
}
2019-02-14 17:18:35 +01:00
2019-08-11 16:38:20 +03:00
if ( is_connected ( ) ) {
m_connect_side_role = Role : : Connected ;
2019-07-20 11:10:46 +02:00
return KSuccess ;
2019-08-11 16:38:20 +03:00
}
2019-07-20 11:10:46 +02:00
2019-08-11 16:38:20 +03:00
if ( current - > block < Thread : : ConnectBlocker > ( description ) = = Thread : : BlockResult : : InterruptedBySignal ) {
m_connect_side_role = Role : : None ;
2019-07-20 11:10:46 +02:00
return KResult ( - EINTR ) ;
2019-08-11 16:38:20 +03:00
}
2019-07-20 11:10:46 +02:00
2019-08-10 13:17:00 +10:00
# ifdef DEBUG_LOCAL_SOCKET
kprintf ( " %s(%u) LocalSocket{%p} connect(%s) status is %s \n " , current - > process ( ) . name ( ) . characters ( ) , current - > pid ( ) , this , safe_address , to_string ( setup_state ( ) ) ) ;
# endif
2019-08-11 16:38:20 +03:00
if ( ! is_connected ( ) ) {
m_connect_side_role = Role : : None ;
2019-07-20 11:10:46 +02:00
return KResult ( - ECONNREFUSED ) ;
2019-08-11 16:38:20 +03:00
}
m_connect_side_role = Role : : Connected ;
2019-07-20 11:10:46 +02:00
return KSuccess ;
2019-02-14 15:55:19 +01:00
}
2019-02-14 16:01:08 +01:00
2019-08-06 23:40:38 +10:00
KResult LocalSocket : : listen ( int backlog )
{
LOCKER ( lock ( ) ) ;
if ( type ( ) ! = SOCK_STREAM )
return KResult ( - EOPNOTSUPP ) ;
set_backlog ( backlog ) ;
2019-08-11 16:38:20 +03:00
m_connect_side_role = m_role = Role : : Listener ;
2019-08-06 23:40:38 +10:00
kprintf ( " LocalSocket{%p} listening with backlog=%d \n " , this , backlog ) ;
return KSuccess ;
}
2019-06-13 22:03:04 +02:00
void LocalSocket : : attach ( FileDescription & description )
2019-02-17 00:13:47 +01:00
{
2019-08-11 16:28:18 +03:00
ASSERT ( ! m_accept_side_fd_open ) ;
2019-08-11 16:38:20 +03:00
if ( m_connect_side_role = = Role : : None ) {
ASSERT ( m_connect_side_fd = = nullptr ) ;
m_connect_side_fd = & description ;
} else {
ASSERT ( m_connect_side_fd ! = & description ) ;
2019-08-11 16:28:18 +03:00
m_accept_side_fd_open = true ;
2019-02-17 11:00:35 +01:00
}
}
2019-06-13 22:03:04 +02:00
void LocalSocket : : detach ( FileDescription & description )
2019-02-17 11:00:35 +01:00
{
2019-08-11 16:38:20 +03:00
if ( m_connect_side_fd = = & description ) {
m_connect_side_fd = nullptr ;
} else {
2019-08-11 16:28:18 +03:00
ASSERT ( m_accept_side_fd_open ) ;
m_accept_side_fd_open = false ;
2019-02-17 11:00:35 +01:00
}
2019-02-17 00:13:47 +01:00
}
2019-06-13 22:03:04 +02:00
bool LocalSocket : : can_read ( FileDescription & description ) const
2019-02-14 16:01:08 +01:00
{
2019-08-11 16:38:20 +03:00
auto role = this - > role ( description ) ;
if ( role = = Role : : Listener )
2019-02-14 16:03:37 +01:00
return can_accept ( ) ;
2019-08-11 16:38:20 +03:00
if ( role = = Role : : Accepted )
2019-06-13 22:03:04 +02:00
return ! has_attached_peer ( description ) | | ! m_for_server . is_empty ( ) ;
2019-08-11 16:38:20 +03:00
if ( role = = Role : : Connected )
2019-06-13 22:03:04 +02:00
return ! has_attached_peer ( description ) | | ! m_for_client . is_empty ( ) ;
2019-02-17 00:13:47 +01:00
ASSERT_NOT_REACHED ( ) ;
2019-02-14 16:01:08 +01:00
}
2019-06-13 22:03:04 +02:00
bool LocalSocket : : has_attached_peer ( const FileDescription & description ) const
2019-05-20 02:54:52 +02:00
{
2019-08-11 16:38:20 +03:00
auto role = this - > role ( description ) ;
if ( role = = Role : : Accepted )
return m_connect_side_fd ! = nullptr ;
if ( role = = Role : : Connected )
2019-08-11 16:28:18 +03:00
return m_accept_side_fd_open ;
2019-05-20 02:54:52 +02:00
ASSERT_NOT_REACHED ( ) ;
}
2019-06-13 22:03:04 +02:00
bool LocalSocket : : can_write ( FileDescription & description ) const
2019-02-14 16:01:08 +01:00
{
2019-08-11 16:38:20 +03:00
auto role = this - > role ( description ) ;
if ( role = = Role : : Accepted )
2019-10-18 14:55:04 +02:00
return ! has_attached_peer ( description ) | | m_for_client . space_for_writing ( ) ;
2019-08-11 16:38:20 +03:00
if ( role = = Role : : Connected )
2019-10-18 14:55:04 +02:00
return ! has_attached_peer ( description ) | | m_for_server . space_for_writing ( ) ;
2019-02-17 00:13:47 +01:00
ASSERT_NOT_REACHED ( ) ;
2019-02-14 16:01:08 +01:00
}
2019-03-12 15:51:42 +01:00
2019-06-13 22:03:04 +02:00
ssize_t LocalSocket : : sendto ( FileDescription & description , const void * data , size_t data_size , int , const sockaddr * , socklen_t )
2019-03-12 15:51:42 +01:00
{
2019-08-05 10:03:19 +02:00
if ( ! has_attached_peer ( description ) )
return - EPIPE ;
2019-08-11 16:38:20 +03:00
auto role = this - > role ( description ) ;
if ( role = = Role : : Accepted )
2019-08-05 10:03:19 +02:00
return m_for_client . write ( ( const u8 * ) data , data_size ) ;
2019-08-11 16:38:20 +03:00
if ( role = = Role : : Connected )
2019-08-05 10:03:19 +02:00
return m_for_server . write ( ( const u8 * ) data , data_size ) ;
ASSERT_NOT_REACHED ( ) ;
2019-03-12 15:51:42 +01:00
}
2019-03-12 17:27:07 +01:00
2019-09-22 21:30:30 +02:00
DoubleBuffer & LocalSocket : : buffer_for ( FileDescription & description )
2019-03-12 17:27:07 +01:00
{
2019-08-11 16:38:20 +03:00
auto role = this - > role ( description ) ;
2019-09-22 21:30:30 +02:00
if ( role = = Role : : Accepted )
return m_for_server ;
if ( role = = Role : : Connected )
return m_for_client ;
ASSERT_NOT_REACHED ( ) ;
}
ssize_t LocalSocket : : recvfrom ( FileDescription & description , void * buffer , size_t buffer_size , int , sockaddr * , socklen_t * )
{
auto & buffer_for_me = buffer_for ( description ) ;
if ( ! description . is_blocking ( ) ) {
if ( buffer_for_me . is_empty ( ) ) {
if ( ! has_attached_peer ( description ) )
return 0 ;
return - EAGAIN ;
2019-08-05 10:03:19 +02:00
}
2019-09-22 21:30:30 +02:00
} else if ( ! can_read ( description ) ) {
auto result = current - > block < Thread : : ReceiveBlocker > ( description ) ;
if ( result = = Thread : : BlockResult : : InterruptedBySignal )
return - EINTR ;
2019-08-05 10:03:19 +02:00
}
2019-09-22 21:30:30 +02:00
if ( ! has_attached_peer ( description ) & & buffer_for_me . is_empty ( ) )
return 0 ;
ASSERT ( ! buffer_for_me . is_empty ( ) ) ;
return buffer_for_me . read ( ( u8 * ) buffer , buffer_size ) ;
2019-03-12 17:27:07 +01:00
}
2019-08-10 18:55:54 +03:00
StringView LocalSocket : : socket_path ( ) const
{
int len = strnlen ( m_address . sun_path , sizeof ( m_address . sun_path ) ) ;
return { m_address . sun_path , len } ;
}
2019-08-10 19:10:36 +03:00
String LocalSocket : : absolute_path ( const FileDescription & description ) const
{
StringBuilder builder ;
builder . append ( " socket: " ) ;
builder . append ( socket_path ( ) ) ;
switch ( role ( description ) ) {
case Role : : Listener :
builder . append ( " (listening) " ) ;
break ;
case Role : : Accepted :
builder . appendf ( " (accepted from pid %d) " , origin_pid ( ) ) ;
break ;
case Role : : Connected :
builder . appendf ( " (connected to pid %d) " , acceptor_pid ( ) ) ;
break ;
case Role : : Connecting :
builder . append ( " (connecting) " ) ;
break ;
default :
break ;
}
return builder . to_string ( ) ;
}