#pragma once #include #include #include 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> An error, or a new server object. */ static Result> 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 Whether the operation succeded. */ Result 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 An error, or the number of bytes read. */ Result 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 Whether the operation succeded. */ template Result 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 An error, or the number of bytes actually sent. */ Result 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 Whether the operation succeded. */ template Result 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> An error, or a handle to the new connection. */ Result> accept(); ~LocalServer(); private: int m_fd; bool m_blocking; }; }