diff options
| author | Nicolas James <Eele1Ephe7uZahRie@tutanota.com> | 2025-02-12 21:57:46 +1100 |
|---|---|---|
| committer | Nicolas James <Eele1Ephe7uZahRie@tutanota.com> | 2025-02-12 21:57:46 +1100 |
| commit | e4483eca01b48b943cd0461e24a74ae1a3139ed4 (patch) | |
| tree | ed58c3c246e3af1af337697695d780aa31f6ad9a /src/shared/net/connection.hh | |
| parent | 1cc08c51eb4b0f95c30c0a98ad1fc5ad3459b2df (diff) | |
Update to most recent version (old initial commit)
Diffstat (limited to 'src/shared/net/connection.hh')
| -rw-r--r-- | src/shared/net/connection.hh | 211 |
1 files changed, 38 insertions, 173 deletions
diff --git a/src/shared/net/connection.hh b/src/shared/net/connection.hh index 79146af..70ed6e4 100644 --- a/src/shared/net/connection.hh +++ b/src/shared/net/connection.hh @@ -2,208 +2,73 @@ #define SHARED_NET_CONNECTION_HH_ #include <algorithm> +#include <ctype.h> #include <optional> #include <string> +#include <type_traits> +#include <list> #include "shared/net/net.hh" +#include "shared/net/packet.hh" #include "shared/net/proto.hh" namespace shared { namespace net { +using socket_t = int; + class connection { +public: + using upacket_t = std::shared_ptr<upacket>; + using rpacket_t = std::shared_ptr<rpacket>; + private: + static constexpr std::size_t MAX_PACKET_SIZE = 65536; + struct sockets { - int rsock; - int usock; // connected in constructor, no need to use sendto or revfrom + socket_t rsock; + socket_t usock; // connected in constructor std::string address; std::string port; - - sockets(const int r, const int u, const std::string& a, - const std::string& p) - : rsock(r), usock(u), address(a), port(p) {} }; std::optional<sockets> socks; std::optional<std::string> bad_reason; + std::list<upacket_t> upackets; + std::list<rpacket_t> rpackets; private: - struct packet_header { - std::uint32_t size; - }; - - // Data has a non-serialised header, and variable length serialised - // protobuf content. - static std::string packet_to_data(const proto::packet& packet) { - - std::string data; - packet.SerializeToString(&data); - shared::compress_string(data); - - packet_header header{.size = htonl(static_cast<std::uint32_t>( - std::size(data) + sizeof(packet_header)))}; - - return std::string{reinterpret_cast<char*>(&header), - reinterpret_cast<char*>(&header) + sizeof(header)} + - std::move(data); - } - - void send_sock_packet(const int sock, const proto::packet& packet) { - if (!this->good()) { - return; - } - - const std::string data = packet_to_data(packet); - - if (send(sock, std::data(data), std::size(data), 0) == -1) { - this->bad_reason = shared::net::get_errno_error(); - } - } + bool maybe_send(const packet& packet, const socket_t& sock) noexcept; public: - connection(const int rsock) { - using namespace shared::net; - - const std::string peer_address = get_socket_peer_address(rsock); - const std::string peer_port = get_socket_peer_port(rsock); - - // Open up a connected usock based on the state of the connected rsock. - const int usock = [&peer_address, &peer_port, &rsock]() -> int { - constexpr addrinfo hints = {.ai_flags = AI_PASSIVE, - .ai_family = AF_INET, - .ai_socktype = SOCK_DGRAM}; - const std::string host_address = get_socket_host_address(rsock); - const std::string host_port = get_socket_host_port(rsock); - const auto host_info = - get_addr_info(host_address, host_port, &hints); - const int usock = make_socket(host_info.get()); - bind_socket(usock, host_info.get()); - - const auto peer_info = - get_addr_info(peer_address, peer_port, &hints); - connect_socket(usock, peer_info.get()); - - return usock; - }(); - - nonblock_socket(usock); - nonblock_socket(rsock); - - this->socks.emplace(rsock, usock, peer_address, peer_port); - } - - // We do not want to copy this object! - // We use std::nullopt to determine if this object has been moved and if we - // should close its sockets. + connection(const socket_t& rsock); // requires connected rsocket connection(const connection&) = delete; - connection(connection&& other) noexcept { - std::swap(this->socks, other.socks); - std::swap(this->bad_reason, other.bad_reason); - other.socks.reset(); - } - connection& operator=(connection&& other) noexcept { - std::swap(this->socks, other.socks); - std::swap(this->bad_reason, other.bad_reason); - other.socks.reset(); - return *this; - } - ~connection() noexcept { - if (this->socks.has_value()) { - shared::net::close_socket(socks->rsock); - shared::net::close_socket(socks->usock); - } - } + connection(connection&& other) noexcept; + connection& operator=(connection&& other) noexcept; + ~connection() noexcept; - // Getters. - bool good() const noexcept { return !bad_reason.has_value(); } - std::string get_bad_reason() const noexcept { - return this->bad_reason.value(); +public: + bool good() const noexcept { + return !bad_reason.has_value() && this->socks.has_value(); } + std::string get_bad_reason() const noexcept { return *this->bad_reason; } std::string get_address() const noexcept { return this->socks->address; } public: - // Send does nothing if good() returns false! - // Returns whether or not we were able to send our packet. - void rsend_packet(const proto::packet& packet) noexcept { - return send_sock_packet(this->socks->rsock, packet); - } - void usend_packet(const proto::packet& packet) noexcept { - return send_sock_packet(this->socks->usock, packet); - } - std::optional<proto::packet> rrecv_packet() noexcept { - const int sock = this->socks->rsock; - - // Get the size of the backlog, early out of there's nothing there yet. - const auto backlog_size = shared::net::get_backlog_size(sock); - if (backlog_size < sizeof(packet_header)) { - return std::nullopt; - } - - // Read for the packet headers and get the claimed size. Early out if - // our stream isn't big enough for that yet. - packet_header header = {}; - recv(sock, &header, sizeof(header), MSG_PEEK); - const std::uint32_t read_packet_size = ntohl(header.size); - if (backlog_size < read_packet_size) { - return std::nullopt; - } - - // Read the actual packet now, based on our claimed size. - std::string data; - data.reserve(read_packet_size); - if (read(sock, std::data(data), read_packet_size) == -1) { - this->bad_reason = shared::net::get_errno_error(); - return std::nullopt; - } - - data = std::string{ - reinterpret_cast<char*>(std::data(data)) + sizeof(packet_header), - reinterpret_cast<char*>(std::data(data)) + read_packet_size}; - shared::decompress_string(data); + // When an identical packet is sent to multiple people, the functions using + // rpacket_t should be used to avoid unnecessary compression. + void rsend_packet(const rpacket_t& packet) noexcept; + void usend_packet(const upacket_t& packet) noexcept; + void rsend_packet(rpacket&& packet) noexcept; + void usend_packet(upacket&& packet) noexcept; - // Parse the packet, ignoring the header. - proto::packet packet; - if (!packet.ParseFromString(data)) { - return std::nullopt; - } - - return packet; - } - std::optional<proto::packet> urecv_packet() noexcept { - const int sock = this->socks->usock; - - restart: - const auto packet_size = shared::net::get_backlog_size(sock); - - if (packet_size == 0) { - return std::nullopt; - } - - std::string data; - data.reserve(packet_size); - if (recv(sock, std::data(data), packet_size, 0) == -1) { - this->bad_reason = shared::net::get_errno_error(); - return std::nullopt; - } - - data = std::string{ - reinterpret_cast<char*>(std::data(data)) + sizeof(packet_header), - reinterpret_cast<char*>(std::data(data)) + packet_size}; - shared::decompress_string(data); - - proto::packet packet; - if (!packet.ParseFromString(data)) { - goto restart; - } +public: + std::optional<proto::packet> rrecv_packet() noexcept; + std::optional<proto::packet> urecv_packet() noexcept; + std::optional<proto::packet> recv_packet() noexcept; // from either - return packet; - } - // Gets packets from r/u streams, doesn't care which. - std::optional<proto::packet> recv_packet() noexcept { - if (const auto ret = urecv_packet(); ret.has_value()) { - return ret; - } - return rrecv_packet(); - } +public: + void poll(); // call to send potentially queued packets + void close(); // call to close sockets }; } // namespace net |
