#include "net/UnixSocket.h" #include #include 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 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 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 bind_socket_to_fs(const char* path, Credentials auth, SharedPtr working_directory, SharedPtr 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 UnixSocket::bind(SharedPtr 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 UnixSocket::connect(struct sockaddr*, socklen_t) { return err(ENOSYS); }