88 lines
2.2 KiB
C++
88 lines
2.2 KiB
C++
|
#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;
|
||
|
}
|
||
|
}
|