Skip to content
Snippets Groups Projects

Draft: Resolve "Unix Socket Server schreiben"

Merged Leon Dietrich requested to merge 3-unix-socket-server-schreiben into master
2 files
+ 40
3
Compare changes
  • Side-by-side
  • Inline
Files
2
+ 99
0
#include "net/unix_socket_server.hpp"
#include <filesystem>
#include <sstream>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include "net/async_fd.hpp"
#include "net/netio_exception.hpp"
#include "net/socket_utils.hpp"
#include "net/tcp_client.hpp"
namespace rmrf::net {
static std::string get_unix_socket_path(const socketaddr& addr) {
if (addr.family() != AF_UNIX) {
return {};
}
return std::string(((sockaddr_un*) addr.ptr())->sun_path);
}
static auto_fd construct_server_fd(const socketaddr& addr) {
if (addr.family() != AF_UNIX) {
throw netio_exception("Expected a UNIX socket file path.");
}
// man 7 unix suggests the ussage of SOCK_SEQPACKET, but we'd loose the ability to distinguish multiple clients if we do so
auto_fd socket_fd{socket(addr.family(), SOCK_STREAM, 0)};
if (!socket_fd.valid()) {
throw netio_exception("Failed to create UNIX socket. Do you have the permissions to do this?");
}
if (auto error = bind(socket_fd.get(), addr.ptr(), addr.size()); error != 0) {
std::stringstream ss;
ss << "Failed to bind to socket " + addr.str() << ".";
const auto p = std::filesystem::path(get_unix_socket_path(addr));
if (std::filesystem::exists(p)) {
ss << " Reason: The file already exists.";
if (std::filesystem::is_socket(p)) {
ss << " It is also a socket. Is the application already running?";
}
} else {
ss << " Is there buffer space avaiable and do you have the permission to create a socket there?";
}
throw netio_exception(ss.str());
}
make_socket_nonblocking(socket_fd);
if (listen(socket_fd.get(), 5) == -1) {
// We already created the socket and close won't remove the file thus we need to unlink it.
unlink(get_unix_socket_path(addr).c_str());
throw netio_exception("Failed to enable listening mode for raw socket");
}
return socket_fd;
}
unix_socket_server::unix_socket_server(
const socketaddr& socket_identifier,
async_server_socket::accept_handler_type client_listener_
) : async_server_socket{construct_server_fd(socket_identifier)}, socket_path{get_unix_socket_path(socket_identifier)} {
this->set_accept_handler(client_listener_);
}
unix_socket_server::~unix_socket_server() {
if (this->socket_path.length() > 0) {
// We're ignoring potential errors as there's nothing we can do about it anyway.
unlink(this->socket_path.c_str());
}
}
std::shared_ptr<connection_client> unix_socket_server::await_raw_socket_incomming(const auto_fd& server_socket) {
auto client_socket = auto_fd{accept(server_socket.get(), nullptr, nullptr)};
if (!client_socket.valid()) {
throw netio_exception("Failed to accept incomming client to unix socket.");
}
make_socket_nonblocking(client_socket);
const socketaddr own_address{}, peer_address{};
return std::make_shared<tcp_client>(
this->get_locked_destructor_callback(),
std::move(client_socket),
own_address,
peer_address);
}
}
Loading