Luna/kernel/src/net/UnixSocket.cpp

105 lines
2.8 KiB
C++
Raw Normal View History

#include "net/UnixSocket.h"
#include <luna/PathParser.h>
#include <thread/Scheduler.h>
UnixSocket::UnixSocket()
{
}
UnixSocket::UnixSocket(UnixSocket* peer) : m_state(State::Connected), m_peer(peer)
{
}
UnixSocket::~UnixSocket()
{
if (m_peer)
{
m_peer->m_peer = nullptr;
m_peer->m_state = State::Reset;
}
}
void UnixSocket::connect_to_peer(UnixSocket* peer)
{
m_peer = peer;
m_state = State::Connected;
}
Result<usize> UnixSocket::send(const u8* buf, usize length, int)
{
if (m_state == State::Reset) return err(ECONNRESET);
if (m_state != State::Connected) return err(ENOTCONN);
check(m_peer);
TRY(m_peer->m_data.append_data(buf, length));
return length;
}
Result<usize> UnixSocket::recv(u8* buf, usize length, int) const
{
if (m_state == State::Reset) return err(ECONNRESET);
if (m_state != State::Connected) return err(ENOTCONN);
return m_data.dequeue_data(buf, length);
}
static Result<void> bind_socket_to_fs(const char* path, Credentials auth, SharedPtr<VFS::Inode> working_directory,
SharedPtr<UnixSocket> socket)
{
auto parent_path = TRY(PathParser::dirname(path));
auto parent_inode = TRY(VFS::resolve_path(parent_path.chars(), auth, working_directory));
if (!VFS::can_write(parent_inode, auth)) return err(EACCES);
auto child_name = TRY(PathParser::basename(path));
TRY(VFS::validate_filename(child_name.view()));
socket->set_inode_number(TRY(parent_inode->fs()->allocate_inode_number()));
socket->set_fs(parent_inode->fs());
return parent_inode->add_entry(socket, child_name.chars());
}
Result<void> UnixSocket::bind(SharedPtr<Socket> socket, struct sockaddr* addr, socklen_t addrlen)
{
if (!addr) return err(EDESTADDRREQ);
if (addr->sa_family != AF_UNIX) return err(EAFNOSUPPORT);
if ((usize)addrlen > sizeof(sockaddr_un)) return err(EINVAL);
if (m_state == State::Connected) return err(EISCONN);
if (m_state != State::Inactive) return err(EINVAL);
struct sockaddr_un* un_address = (struct sockaddr_un*)addr;
String path = TRY(String::from_string_view(
StringView::from_fixed_size_cstring(un_address->sun_path, addrlen - sizeof(sa_family_t))));
auto* current = Scheduler::current();
socket->chmod(0777 & ~current->umask);
socket->chown(current->auth.euid, current->auth.egid);
auto rc = bind_socket_to_fs(path.chars(), current->auth, current->current_directory, socket);
if (rc.has_error())
{
if (rc.error() == EEXIST) return err(EADDRINUSE);
return rc.release_error();
}
memcpy(&m_addr, un_address, addrlen);
m_addrlen = addrlen;
m_state = State::Bound;
return {};
}
Result<void> UnixSocket::connect(struct sockaddr*, socklen_t)
{
return err(ENOSYS);
}