Compare commits
3 Commits
5c96a31cd8
...
7a2acce8fd
Author | SHA1 | Date | |
---|---|---|---|
7a2acce8fd | |||
c779ef84ef | |||
d98385088a |
@ -65,6 +65,10 @@ class Socket : public VFS::FileInode
|
|||||||
m_metadata.nlinks--;
|
m_metadata.nlinks--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool can_accept_connections() const = 0;
|
||||||
|
|
||||||
|
virtual bool can_read_data() const = 0;
|
||||||
|
|
||||||
virtual ~Socket() = default;
|
virtual ~Socket() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -17,6 +17,16 @@ class UnixSocket : public Socket
|
|||||||
return (m_state == Connected || m_state == Reset) && !m_data.size();
|
return (m_state == Connected || m_state == Reset) && !m_data.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool can_read_data() const override
|
||||||
|
{
|
||||||
|
return (m_state == Connected || m_state == Reset) && m_data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool can_accept_connections() const override
|
||||||
|
{
|
||||||
|
return !m_listen_queue.is_empty();
|
||||||
|
}
|
||||||
|
|
||||||
Result<usize> send(const u8*, usize, int) override;
|
Result<usize> send(const u8*, usize, int) override;
|
||||||
Result<usize> recv(u8*, usize, int) const override;
|
Result<usize> recv(u8*, usize, int) const override;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
|
#include "net/Socket.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include <bits/poll.h>
|
#include <bits/poll.h>
|
||||||
@ -43,12 +44,27 @@ Result<u64> sys_poll(Registers* regs, SyscallArgs args)
|
|||||||
auto& inode = inodes[i];
|
auto& inode = inodes[i];
|
||||||
if (!inode) continue;
|
if (!inode) continue;
|
||||||
|
|
||||||
if (kfds[i].events & POLLIN && !inode->will_block_if_read())
|
if (kfds[i].events & POLLIN)
|
||||||
|
{
|
||||||
|
if (inode->type() == VFS::InodeType::Socket)
|
||||||
|
{
|
||||||
|
auto socket = (Socket*)inode.ptr();
|
||||||
|
if (socket->can_read_data() || socket->can_accept_connections())
|
||||||
{
|
{
|
||||||
fds_with_events++;
|
fds_with_events++;
|
||||||
kfds[i].revents |= POLLIN;
|
kfds[i].revents |= POLLIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!inode->will_block_if_read())
|
||||||
|
{
|
||||||
|
fds_with_events++;
|
||||||
|
kfds[i].revents |= POLLIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!fds_with_events && (timeout > 0 || infinite))
|
if (!fds_with_events && (timeout > 0 || infinite))
|
||||||
{
|
{
|
||||||
|
@ -16,7 +16,7 @@ template <typename T, usize Size> class CircularQueue
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_empty()
|
bool is_empty() const
|
||||||
{
|
{
|
||||||
return m_tail.load() == m_head.load();
|
return m_tail.load() == m_head.load();
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@ template <typename T> class DynamicCircularQueue
|
|||||||
if (m_data) free_impl(m_data);
|
if (m_data) free_impl(m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_empty()
|
bool is_empty() const
|
||||||
{
|
{
|
||||||
return m_tail.load() == m_head.load();
|
return m_tail.load() == m_head.load();
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ set(SOURCES
|
|||||||
src/Path.cpp
|
src/Path.cpp
|
||||||
src/Mode.cpp
|
src/Mode.cpp
|
||||||
src/Prompt.cpp
|
src/Prompt.cpp
|
||||||
|
src/LocalServer.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(os ${SOURCES})
|
add_library(os ${SOURCES})
|
||||||
|
132
libos/include/os/LocalServer.h
Normal file
132
libos/include/os/LocalServer.h
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <luna/Result.h>
|
||||||
|
#include <luna/SharedPtr.h>
|
||||||
|
#include <luna/StringView.h>
|
||||||
|
|
||||||
|
namespace os
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief A local domain server, used to communicate between processes on the same machine.
|
||||||
|
*/
|
||||||
|
class LocalServer : public Shareable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Create a new server object and bind it to a local address.
|
||||||
|
*
|
||||||
|
* @param path The path to use for the server socket.
|
||||||
|
* @param blocking Whether the server should block if no connections are available when calling accept().
|
||||||
|
* @return Result<SharedPtr<LocalServer>> An error, or a new server object.
|
||||||
|
*/
|
||||||
|
static Result<SharedPtr<LocalServer>> create(StringView path, bool blocking);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Activate the server and start listening for connections.
|
||||||
|
*
|
||||||
|
* @param backlog The number of unaccepted connections to keep.
|
||||||
|
* @return Result<void> Whether the operation succeded.
|
||||||
|
*/
|
||||||
|
Result<void> listen(int backlog);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the underlying socket file descriptor used by this object.
|
||||||
|
*
|
||||||
|
* @return int The file descriptor.
|
||||||
|
*/
|
||||||
|
int fd() const
|
||||||
|
{
|
||||||
|
return m_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An interface to communicate with clients connected to a local server.
|
||||||
|
*/
|
||||||
|
class Client : public Shareable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Read arbitrary data from the client. The call will block if there is no data and the parent server
|
||||||
|
* object has not been created as non-blocking.
|
||||||
|
*
|
||||||
|
* @param buf The buffer to read data into.
|
||||||
|
* @param length The maximum amount of bytes to read.
|
||||||
|
* @return Result<usize> An error, or the number of bytes read.
|
||||||
|
*/
|
||||||
|
Result<usize> recv(u8* buf, usize length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read an object from the client. The call will block if there is no data and the parent server
|
||||||
|
* object has not been created as non-blocking.
|
||||||
|
*
|
||||||
|
* @tparam T The type of the object.
|
||||||
|
* @param out A reference to the object to read data into.
|
||||||
|
* @return Result<void> Whether the operation succeded.
|
||||||
|
*/
|
||||||
|
template <typename T> Result<void> recv_typed(T& out)
|
||||||
|
{
|
||||||
|
TRY(recv((u8*)&out, sizeof(T)));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send arbitrary data to the client.
|
||||||
|
*
|
||||||
|
* @param buf The buffer to send data from.
|
||||||
|
* @param length The amount of bytes to send.
|
||||||
|
* @return Result<usize> An error, or the number of bytes actually sent.
|
||||||
|
*/
|
||||||
|
Result<usize> send(const u8* buf, usize length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send an object to the client.
|
||||||
|
*
|
||||||
|
* @tparam T The type of the object.
|
||||||
|
* @param out A reference to the object to send data from.
|
||||||
|
* @return Result<void> Whether the operation succeded.
|
||||||
|
*/
|
||||||
|
template <typename T> Result<void> send_typed(const T& out)
|
||||||
|
{
|
||||||
|
TRY(send((const u8*)&out, sizeof(T)));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disconnect from the attached client.
|
||||||
|
*
|
||||||
|
* This will make any further reads on the client return ECONNRESET, and will make this object invalid.
|
||||||
|
*/
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the underlying socket file descriptor used by this object.
|
||||||
|
*
|
||||||
|
* @return int The file descriptor.
|
||||||
|
*/
|
||||||
|
int fd() const
|
||||||
|
{
|
||||||
|
return m_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
Client(int fd);
|
||||||
|
~Client();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Accept a new incoming connection and return a handle to it. If there are no incoming connections,
|
||||||
|
* accept() either blocks until there is one (if the object was created with blocking=true), or returns EAGAIN
|
||||||
|
* (if the object was created with blocking=false).
|
||||||
|
*
|
||||||
|
* @return Result<SharedPtr<Client>> An error, or a handle to the new connection.
|
||||||
|
*/
|
||||||
|
Result<SharedPtr<Client>> accept();
|
||||||
|
|
||||||
|
~LocalServer();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_fd;
|
||||||
|
bool m_blocking;
|
||||||
|
};
|
||||||
|
}
|
87
libos/src/LocalServer.cpp
Normal file
87
libos/src/LocalServer.cpp
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <os/FileSystem.h>
|
||||||
|
#include <os/LocalServer.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace os
|
||||||
|
{
|
||||||
|
Result<SharedPtr<LocalServer>> LocalServer::create(StringView path, bool blocking)
|
||||||
|
{
|
||||||
|
auto server = TRY(make_shared<LocalServer>());
|
||||||
|
|
||||||
|
(void)os::FileSystem::remove(path); // We explicitly ignore any error here, either it doesn't exist (which is
|
||||||
|
// fine), or it cannot be removed, which will make bind() fail later.
|
||||||
|
|
||||||
|
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (sockfd < 0) return err(errno);
|
||||||
|
|
||||||
|
struct sockaddr_un un;
|
||||||
|
un.sun_family = AF_UNIX;
|
||||||
|
strncpy(un.sun_path, path.chars(), sizeof(un.sun_path));
|
||||||
|
|
||||||
|
if (bind(sockfd, (struct sockaddr*)&un, sizeof(un)) < 0)
|
||||||
|
{
|
||||||
|
close(sockfd);
|
||||||
|
return err(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!blocking) { fcntl(sockfd, F_SETFL, O_NONBLOCK); }
|
||||||
|
server->m_blocking = blocking;
|
||||||
|
|
||||||
|
fcntl(sockfd, F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
|
server->m_fd = sockfd;
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> LocalServer::listen(int backlog)
|
||||||
|
{
|
||||||
|
if (::listen(m_fd, backlog) < 0) return err(errno);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SharedPtr<LocalServer::Client>> LocalServer::accept()
|
||||||
|
{
|
||||||
|
int fd = ::accept(m_fd, nullptr, nullptr);
|
||||||
|
if (fd < 0) return err(errno);
|
||||||
|
if (!m_blocking) fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||||
|
return make_shared<Client>(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalServer::~LocalServer()
|
||||||
|
{
|
||||||
|
close(m_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalServer::Client::Client(int fd) : m_fd(fd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalServer::Client::~Client()
|
||||||
|
{
|
||||||
|
if (m_fd >= 0) close(m_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<usize> LocalServer::Client::recv(u8* buf, usize length)
|
||||||
|
{
|
||||||
|
ssize_t nread = read(m_fd, buf, length);
|
||||||
|
if (nread < 0) return err(errno);
|
||||||
|
return nread;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<usize> LocalServer::Client::send(const u8* buf, usize length)
|
||||||
|
{
|
||||||
|
ssize_t nwrite = write(m_fd, buf, length);
|
||||||
|
if (nwrite < 0) return err(errno);
|
||||||
|
return nwrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalServer::Client::disconnect()
|
||||||
|
{
|
||||||
|
close(m_fd);
|
||||||
|
m_fd = -1;
|
||||||
|
}
|
||||||
|
}
|
@ -7,18 +7,16 @@
|
|||||||
|
|
||||||
Result<Screen> Screen::open()
|
Result<Screen> Screen::open()
|
||||||
{
|
{
|
||||||
int fd = ::open("/dev/fb0", O_RDWR | O_CLOEXEC);
|
int fd = ::open("/dev/fb0", O_RDWR);
|
||||||
if (fd < 0) return err(errno);
|
if (fd < 0) return err(errno);
|
||||||
|
|
||||||
int width = ioctl(fd, FB_GET_WIDTH);
|
int width = ioctl(fd, FB_GET_WIDTH);
|
||||||
int height = ioctl(fd, FB_GET_HEIGHT);
|
int height = ioctl(fd, FB_GET_HEIGHT);
|
||||||
|
|
||||||
void* p = mmap(nullptr, width * height * BYTES_PER_PIXEL, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
void* p = mmap(nullptr, width * height * BYTES_PER_PIXEL, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
if (p == MAP_FAILED)
|
|
||||||
{
|
|
||||||
close(fd);
|
close(fd);
|
||||||
return err(errno);
|
|
||||||
}
|
if (p == MAP_FAILED) { return err(errno); }
|
||||||
|
|
||||||
Screen screen;
|
Screen screen;
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <moon/Keyboard.h>
|
#include <moon/Keyboard.h>
|
||||||
#include <os/ArgumentParser.h>
|
#include <os/ArgumentParser.h>
|
||||||
#include <os/File.h>
|
#include <os/File.h>
|
||||||
|
#include <os/LocalServer.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -40,6 +41,9 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
auto screen = TRY(Screen::open());
|
auto screen = TRY(Screen::open());
|
||||||
|
|
||||||
|
auto server = TRY(os::LocalServer::create(socket_path, false));
|
||||||
|
TRY(server->listen(20));
|
||||||
|
|
||||||
Mouse mouse_pointer { screen.canvas() };
|
Mouse mouse_pointer { screen.canvas() };
|
||||||
|
|
||||||
ioctl(STDIN_FILENO, TTYSETGFX, 1);
|
ioctl(STDIN_FILENO, TTYSETGFX, 1);
|
||||||
@ -67,14 +71,17 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
ui::Color background = ui::BLACK;
|
ui::Color background = ui::BLACK;
|
||||||
|
|
||||||
|
Vector<SharedPtr<os::LocalServer::Client>> clients;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
struct pollfd fds[] = {
|
struct pollfd fds[] = {
|
||||||
{ .fd = mouse->fd(), .events = POLLIN, .revents = 0 },
|
{ .fd = mouse->fd(), .events = POLLIN, .revents = 0 },
|
||||||
{ .fd = keyboard->fd(), .events = POLLIN, .revents = 0 },
|
{ .fd = keyboard->fd(), .events = POLLIN, .revents = 0 },
|
||||||
|
{ .fd = server->fd(), .events = POLLIN, .revents = 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
int rc = poll(fds, 2, 1000);
|
int rc = poll(fds, 3, 1000);
|
||||||
if (!rc) continue;
|
if (!rc) continue;
|
||||||
if (rc < 0) { os::println("poll: error: %s", strerror(errno)); }
|
if (rc < 0) { os::println("poll: error: %s", strerror(errno)); }
|
||||||
|
|
||||||
@ -90,6 +97,12 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
TRY(keyboard->read_typed(packet));
|
TRY(keyboard->read_typed(packet));
|
||||||
background = ui::Color::from_rgb(0x00, 0x00, packet.key * 2);
|
background = ui::Color::from_rgb(0x00, 0x00, packet.key * 2);
|
||||||
}
|
}
|
||||||
|
if (fds[2].revents & POLLIN)
|
||||||
|
{
|
||||||
|
auto client = TRY(server->accept());
|
||||||
|
os::println("wind: New client connected!");
|
||||||
|
TRY(clients.try_append(client));
|
||||||
|
}
|
||||||
|
|
||||||
screen.canvas().fill(background);
|
screen.canvas().fill(background);
|
||||||
mouse_pointer.draw(screen.canvas());
|
mouse_pointer.draw(screen.canvas());
|
||||||
|
Loading…
Reference in New Issue
Block a user