forked from Bananymous/banan-os
Kernel/LibC: Implement basic socket binding
This commit is contained in:
@@ -56,6 +56,12 @@ namespace Kernel
|
||||
return true;
|
||||
}
|
||||
|
||||
void Inode::on_close()
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
on_close_impl();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<Inode>> Inode::find_inode(BAN::StringView name)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
@@ -110,6 +116,14 @@ namespace Kernel
|
||||
return link_target_impl();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Inode::bind(const sockaddr* address, socklen_t address_len)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
if (!mode().ifsock())
|
||||
return BAN::Error::from_errno(ENOTSOCK);
|
||||
return bind_impl(address, address_len);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> Inode::read(off_t offset, BAN::ByteSpan buffer)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
@@ -68,11 +68,39 @@ namespace Kernel
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<NetworkSocket>> NetworkManager::create_socket(SocketType type, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
|
||||
|
||||
if (type != SocketType::DGRAM)
|
||||
return BAN::Error::from_errno(EPROTOTYPE);
|
||||
|
||||
auto udp_socket = TRY(UDPSocket::create(mode, uid, gid));
|
||||
auto udp_socket = TRY(UDPSocket::create(mode | Inode::Mode::IFSOCK, uid, gid));
|
||||
return BAN::RefPtr<NetworkSocket>(udp_socket);
|
||||
}
|
||||
|
||||
void NetworkManager::unbind_socket(uint16_t port, BAN::RefPtr<NetworkSocket> socket)
|
||||
{
|
||||
if (m_bound_sockets.contains(port))
|
||||
{
|
||||
ASSERT(m_bound_sockets[port].valid());
|
||||
ASSERT(m_bound_sockets[port].lock() == socket);
|
||||
m_bound_sockets.remove(port);
|
||||
}
|
||||
NetworkManager::get().remove_from_cache(socket);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> NetworkManager::bind_socket(uint16_t port, BAN::RefPtr<NetworkSocket> socket)
|
||||
{
|
||||
if (m_interfaces.empty())
|
||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||
if (m_bound_sockets.contains(port))
|
||||
return BAN::Error::from_errno(EADDRINUSE);
|
||||
|
||||
// FIXME: actually determine proper interface
|
||||
auto interface = m_interfaces.front();
|
||||
TRY(m_bound_sockets.insert(port, socket));
|
||||
socket->bind_interface_and_port(interface.ptr(), port);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,11 +13,30 @@ namespace Kernel
|
||||
)
|
||||
{ }
|
||||
|
||||
void NetworkSocket::bind_interface(NetworkInterface* interface)
|
||||
NetworkSocket::~NetworkSocket()
|
||||
{
|
||||
}
|
||||
|
||||
void NetworkSocket::on_close_impl()
|
||||
{
|
||||
if (m_interface)
|
||||
NetworkManager::get().unbind_socket(m_port, this);
|
||||
}
|
||||
|
||||
void NetworkSocket::bind_interface_and_port(NetworkInterface* interface, uint16_t port)
|
||||
{
|
||||
ASSERT(!m_interface);
|
||||
ASSERT(interface);
|
||||
m_interface = interface;
|
||||
m_port = port;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> NetworkSocket::bind_impl(const sockaddr* address, socklen_t address_len)
|
||||
{
|
||||
if (address_len != sizeof(sockaddr_in))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
auto* addr_in = reinterpret_cast<const sockaddr_in*>(address);
|
||||
return NetworkManager::get().bind_socket(addr_in->sin_port, this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -276,6 +276,8 @@ namespace Kernel
|
||||
if (m_open_files[fd]->flags & O_WRONLY && m_open_files[fd]->inode->is_pipe())
|
||||
((Pipe*)m_open_files[fd]->inode.ptr())->close_writing();
|
||||
|
||||
m_open_files[fd]->inode->on_close();
|
||||
|
||||
m_open_files[fd].clear();
|
||||
|
||||
return {};
|
||||
|
||||
@@ -901,6 +901,20 @@ namespace Kernel
|
||||
return TRY(m_open_file_descriptors.socket(domain, type, protocol));
|
||||
}
|
||||
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_bind(int socket, const sockaddr* address, socklen_t address_len)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
TRY(validate_pointer_access(address, address_len));
|
||||
|
||||
auto inode = TRY(m_open_file_descriptors.inode_of(socket));
|
||||
if (!inode->mode().ifsock())
|
||||
return BAN::Error::from_errno(ENOTSOCK);
|
||||
|
||||
TRY(inode->bind(address, address_len));
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pipe(int fildes[2])
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
@@ -216,6 +216,9 @@ namespace Kernel
|
||||
case SYS_SOCKET:
|
||||
ret = Process::current().sys_socket((int)arg1, (int)arg2, (int)arg3);
|
||||
break;
|
||||
case SYS_BIND:
|
||||
ret = Process::current().sys_bind((int)arg1, (const sockaddr*)arg2, (socklen_t)arg3);
|
||||
break;
|
||||
default:
|
||||
dwarnln("Unknown syscall {}", syscall);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user