2019-06-07 04:36:51 -03:00
# include <Kernel/FileSystem/FileDescription.h>
2019-04-03 07:25:24 -03:00
# include <Kernel/FileSystem/VirtualFileSystem.h>
2019-06-07 06:43:58 -03:00
# include <Kernel/Net/LocalSocket.h>
# include <Kernel/Process.h>
# include <Kernel/UnixTypes.h>
2019-02-14 11:38:30 -02:00
# include <LibC/errno_numbers.h>
2019-02-14 11:17:38 -02:00
2019-03-01 06:51:58 -03:00
//#define DEBUG_LOCAL_SOCKET
2019-06-21 13:37:47 -03:00
NonnullRefPtr < LocalSocket > LocalSocket : : create ( int type )
2019-02-14 11:17:38 -02:00
{
return adopt ( * new LocalSocket ( type ) ) ;
}
LocalSocket : : LocalSocket ( int type )
: Socket ( AF_LOCAL , type , 0 )
{
2019-03-01 06:51:58 -03:00
# ifdef DEBUG_LOCAL_SOCKET
2019-03-23 18:03:17 -03:00
kprintf ( " %s(%u) LocalSocket{%p} created with type=%u \n " , current - > process ( ) . name ( ) . characters ( ) , current - > pid ( ) , this , type ) ;
2019-03-01 06:51:58 -03:00
# endif
2019-02-14 11:17:38 -02:00
}
LocalSocket : : ~ LocalSocket ( )
{
}
2019-05-20 15:33:03 -03:00
bool LocalSocket : : get_local_address ( sockaddr * address , socklen_t * address_size )
2019-02-14 12:17:30 -02: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 15:33:03 -03:00
bool LocalSocket : : get_peer_address ( sockaddr * address , socklen_t * address_size )
{
return get_local_address ( address , address_size ) ;
}
2019-03-06 18:14:31 -03:00
KResult LocalSocket : : bind ( const sockaddr * address , socklen_t address_size )
2019-02-14 11:38:30 -02:00
{
2019-08-10 00:17:00 -03:00
ASSERT ( setup_state ( ) = = SetupState : : Unstarted ) ;
2019-03-06 18:14:31 -03:00
if ( address_size ! = sizeof ( sockaddr_un ) )
return KResult ( - EINVAL ) ;
if ( address - > sa_family ! = AF_LOCAL )
return KResult ( - EINVAL ) ;
2019-02-14 11:38:30 -02:00
const sockaddr_un & local_address = * reinterpret_cast < const sockaddr_un * > ( address ) ;
2019-08-10 12:49:14 -03:00
char safe_address [ sizeof ( local_address . sun_path ) + 1 ] = { 0 } ;
2019-02-14 11:38:30 -02:00
memcpy ( safe_address , local_address . sun_path , sizeof ( local_address . sun_path ) ) ;
2019-03-01 06:51:58 -03:00
# ifdef DEBUG_LOCAL_SOCKET
2019-03-23 18:03:17 -03:00
kprintf ( " %s(%u) LocalSocket{%p} bind(%s) \n " , current - > process ( ) . name ( ) . characters ( ) , current - > pid ( ) , this , safe_address ) ;
2019-03-01 06:51:58 -03:00
# endif
2019-02-14 11:38:30 -02:00
2019-05-30 15:23:50 -03:00
auto result = VFS : : the ( ) . open ( safe_address , O_CREAT | O_EXCL , S_IFSOCK | 0666 , current - > process ( ) . current_directory ( ) ) ;
2019-03-06 18:14:31 -03:00
if ( result . is_error ( ) ) {
if ( result . error ( ) = = - EEXIST )
return KResult ( - EADDRINUSE ) ;
return result . error ( ) ;
2019-02-14 11:38:30 -02:00
}
2019-03-06 18:14:31 -03:00
m_file = move ( result . value ( ) ) ;
2019-02-14 12:17:30 -02:00
2019-02-14 12:55:19 -02:00
ASSERT ( m_file - > inode ( ) ) ;
m_file - > inode ( ) - > bind_socket ( * this ) ;
2019-02-14 12:17:30 -02:00
m_address = local_address ;
m_bound = true ;
2019-08-10 00:17:00 -03:00
set_setup_state ( SetupState : : Completed ) ;
2019-03-06 18:14:31 -03:00
return KSuccess ;
2019-02-14 11:38:30 -02:00
}
2019-02-14 12:55:19 -02:00
2019-06-13 17:03:04 -03:00
KResult LocalSocket : : connect ( FileDescription & description , const sockaddr * address , socklen_t address_size , ShouldBlock )
2019-02-14 12:55:19 -02:00
{
ASSERT ( ! m_bound ) ;
2019-03-06 18:14:31 -03:00
if ( address_size ! = sizeof ( sockaddr_un ) )
return KResult ( - EINVAL ) ;
if ( address - > sa_family ! = AF_LOCAL )
return KResult ( - EINVAL ) ;
2019-02-14 12:55:19 -02:00
const sockaddr_un & local_address = * reinterpret_cast < const sockaddr_un * > ( address ) ;
2019-08-10 12:49:14 -03:00
char safe_address [ sizeof ( local_address . sun_path ) + 1 ] = { 0 } ;
2019-02-14 12:55:19 -02:00
memcpy ( safe_address , local_address . sun_path , sizeof ( local_address . sun_path ) ) ;
2019-03-01 06:51:58 -03:00
# ifdef DEBUG_LOCAL_SOCKET
2019-03-23 18:03:17 -03:00
kprintf ( " %s(%u) LocalSocket{%p} connect(%s) \n " , current - > process ( ) . name ( ) . characters ( ) , current - > pid ( ) , this , safe_address ) ;
2019-03-01 06:51:58 -03:00
# endif
2019-02-14 12:55:19 -02:00
2019-06-13 17:03:04 -03: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 18:14:31 -03:00
return KResult ( - ECONNREFUSED ) ;
2019-06-13 17:03:04 -03:00
m_file = move ( description_or_error . value ( ) ) ;
2019-03-06 18:14:31 -03:00
2019-02-14 12:55:19 -02:00
ASSERT ( m_file - > inode ( ) ) ;
2019-03-06 18:14:31 -03:00
if ( ! m_file - > inode ( ) - > socket ( ) )
return KResult ( - ECONNREFUSED ) ;
2019-02-14 12:55:19 -02:00
m_address = local_address ;
2019-02-14 14:18:35 -02:00
2019-08-11 10:38:20 -03:00
ASSERT ( m_connect_side_fd = = & description ) ;
m_connect_side_role = Role : : Connecting ;
2019-02-14 14:18:35 -02:00
auto peer = m_file - > inode ( ) - > socket ( ) ;
2019-03-06 18:14:31 -03:00
auto result = peer - > queue_connection_from ( * this ) ;
2019-08-11 10:38:20 -03:00
if ( result . is_error ( ) ) {
m_connect_side_role = Role : : None ;
2019-03-06 18:14:31 -03:00
return result ;
2019-08-11 10:38:20 -03:00
}
2019-02-14 14:18:35 -02:00
2019-08-11 10:38:20 -03:00
if ( is_connected ( ) ) {
m_connect_side_role = Role : : Connected ;
2019-07-20 06:10:46 -03:00
return KSuccess ;
2019-08-11 10:38:20 -03:00
}
2019-07-20 06:10:46 -03:00
2019-08-11 10:38:20 -03:00
if ( current - > block < Thread : : ConnectBlocker > ( description ) = = Thread : : BlockResult : : InterruptedBySignal ) {
m_connect_side_role = Role : : None ;
2019-07-20 06:10:46 -03:00
return KResult ( - EINTR ) ;
2019-08-11 10:38:20 -03:00
}
2019-07-20 06:10:46 -03:00
2019-08-10 00:17:00 -03: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 10:38:20 -03:00
if ( ! is_connected ( ) ) {
m_connect_side_role = Role : : None ;
2019-07-20 06:10:46 -03:00
return KResult ( - ECONNREFUSED ) ;
2019-08-11 10:38:20 -03:00
}
m_connect_side_role = Role : : Connected ;
2019-07-20 06:10:46 -03:00
return KSuccess ;
2019-02-14 12:55:19 -02:00
}
2019-02-14 13:01:08 -02:00
2019-08-06 10:40:38 -03:00
KResult LocalSocket : : listen ( int backlog )
{
LOCKER ( lock ( ) ) ;
if ( type ( ) ! = SOCK_STREAM )
return KResult ( - EOPNOTSUPP ) ;
set_backlog ( backlog ) ;
2019-08-11 10:38:20 -03:00
m_connect_side_role = m_role = Role : : Listener ;
2019-08-06 10:40:38 -03:00
kprintf ( " LocalSocket{%p} listening with backlog=%d \n " , this , backlog ) ;
return KSuccess ;
}
2019-06-13 17:03:04 -03:00
void LocalSocket : : attach ( FileDescription & description )
2019-02-16 21:13:47 -02:00
{
2019-08-11 10:28:18 -03:00
ASSERT ( ! m_accept_side_fd_open ) ;
2019-08-11 10: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 10:28:18 -03:00
m_accept_side_fd_open = true ;
2019-02-17 07:00:35 -03:00
}
}
2019-06-13 17:03:04 -03:00
void LocalSocket : : detach ( FileDescription & description )
2019-02-17 07:00:35 -03:00
{
2019-08-11 10:38:20 -03:00
if ( m_connect_side_fd = = & description ) {
m_connect_side_fd = nullptr ;
} else {
2019-08-11 10:28:18 -03:00
ASSERT ( m_accept_side_fd_open ) ;
m_accept_side_fd_open = false ;
2019-02-17 07:00:35 -03:00
}
2019-02-16 21:13:47 -02:00
}
2019-06-13 17:03:04 -03:00
bool LocalSocket : : can_read ( FileDescription & description ) const
2019-02-14 13:01:08 -02:00
{
2019-08-11 10:38:20 -03:00
auto role = this - > role ( description ) ;
if ( role = = Role : : Listener )
2019-02-14 13:03:37 -02:00
return can_accept ( ) ;
2019-08-11 10:38:20 -03:00
if ( role = = Role : : Accepted )
2019-06-13 17:03:04 -03:00
return ! has_attached_peer ( description ) | | ! m_for_server . is_empty ( ) ;
2019-08-11 10:38:20 -03:00
if ( role = = Role : : Connected )
2019-06-13 17:03:04 -03:00
return ! has_attached_peer ( description ) | | ! m_for_client . is_empty ( ) ;
2019-02-16 21:13:47 -02:00
ASSERT_NOT_REACHED ( ) ;
2019-02-14 13:01:08 -02:00
}
2019-06-13 17:03:04 -03:00
bool LocalSocket : : has_attached_peer ( const FileDescription & description ) const
2019-05-19 21:54:52 -03:00
{
2019-08-11 10: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 10:28:18 -03:00
return m_accept_side_fd_open ;
2019-05-19 21:54:52 -03:00
ASSERT_NOT_REACHED ( ) ;
}
2019-06-13 17:03:04 -03:00
bool LocalSocket : : can_write ( FileDescription & description ) const
2019-02-14 13:01:08 -02:00
{
2019-08-11 10:38:20 -03:00
auto role = this - > role ( description ) ;
if ( role = = Role : : Accepted )
2019-06-13 17:03:04 -03:00
return ! has_attached_peer ( description ) | | m_for_client . bytes_in_write_buffer ( ) < 16384 ;
2019-08-11 10:38:20 -03:00
if ( role = = Role : : Connected )
2019-06-13 17:03:04 -03:00
return ! has_attached_peer ( description ) | | m_for_server . bytes_in_write_buffer ( ) < 16384 ;
2019-02-16 21:13:47 -02:00
ASSERT_NOT_REACHED ( ) ;
2019-02-14 13:01:08 -02:00
}
2019-03-12 11:51:42 -03:00
2019-06-13 17:03:04 -03:00
ssize_t LocalSocket : : sendto ( FileDescription & description , const void * data , size_t data_size , int , const sockaddr * , socklen_t )
2019-03-12 11:51:42 -03:00
{
2019-08-05 05:03:19 -03:00
if ( ! has_attached_peer ( description ) )
return - EPIPE ;
2019-08-11 10:38:20 -03:00
auto role = this - > role ( description ) ;
if ( role = = Role : : Accepted )
2019-08-05 05:03:19 -03:00
return m_for_client . write ( ( const u8 * ) data , data_size ) ;
2019-08-11 10:38:20 -03:00
if ( role = = Role : : Connected )
2019-08-05 05:03:19 -03:00
return m_for_server . write ( ( const u8 * ) data , data_size ) ;
ASSERT_NOT_REACHED ( ) ;
2019-03-12 11:51:42 -03:00
}
2019-03-12 13:27:07 -03:00
2019-06-13 17:03:04 -03:00
ssize_t LocalSocket : : recvfrom ( FileDescription & description , void * buffer , size_t buffer_size , int , sockaddr * , socklen_t * )
2019-03-12 13:27:07 -03:00
{
2019-08-11 10:38:20 -03:00
auto role = this - > role ( description ) ;
if ( role = = Role : : Accepted ) {
2019-08-05 05:03:19 -03:00
if ( ! description . is_blocking ( ) ) {
if ( m_for_server . is_empty ( ) )
return - EAGAIN ;
}
return m_for_server . read ( ( u8 * ) buffer , buffer_size ) ;
}
2019-08-11 10:38:20 -03:00
if ( role = = Role : : Connected ) {
2019-08-05 05:03:19 -03:00
if ( ! description . is_blocking ( ) ) {
if ( m_for_client . is_empty ( ) )
return - EAGAIN ;
}
return m_for_client . read ( ( u8 * ) buffer , buffer_size ) ;
}
ASSERT_NOT_REACHED ( ) ;
2019-03-12 13:27:07 -03:00
}