diff options
| author | Nicolas James <Eele1Ephe7uZahRie@tutanota.com> | 2025-02-12 18:05:18 +1100 |
|---|---|---|
| committer | Nicolas James <Eele1Ephe7uZahRie@tutanota.com> | 2025-02-12 18:05:18 +1100 |
| commit | 1cc08c51eb4b0f95c30c0a98ad1fc5ad3459b2df (patch) | |
| tree | 222dfcd07a1e40716127a347bbfd7119ce3d0984 /src/shared/net/net.cc | |
initial commit
Diffstat (limited to 'src/shared/net/net.cc')
| -rw-r--r-- | src/shared/net/net.cc | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/src/shared/net/net.cc b/src/shared/net/net.cc new file mode 100644 index 0000000..dc78261 --- /dev/null +++ b/src/shared/net/net.cc @@ -0,0 +1,138 @@ +#include "net.hh" + +namespace shared { +namespace net { + +// Some calls use errno, some use strerr. +std::string get_net_error(const int code) noexcept { + return make_string_lower(std::string(gai_strerror(code))); +} + +std::string get_errno_error() noexcept { + return make_string_lower(std::string(strerror(errno))); +} + +std::shared_ptr<addrinfo> get_addr_info(const std::string_view address, + const std::string_view port, + const addrinfo* const hints) { + addrinfo* info; + if (int status = getaddrinfo(address.data(), port.data(), hints, &info)) { + throw std::runtime_error(get_net_error(status)); + } + return std::shared_ptr<addrinfo>{info, [](auto p) { freeaddrinfo(p); }}; +} + +int make_socket(const addrinfo* const info) { + int sock = socket(info->ai_family, info->ai_socktype, info->ai_protocol); + if (sock == -1) { + throw std::runtime_error(get_errno_error()); + } + int enable = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); + return sock; +} + +void bind_socket(const int sock, const addrinfo* const info) { + // Bind to the first we can, otherwise throw. + for (const addrinfo* i = info; i; i = i->ai_next) { + if (bind(sock, info->ai_addr, info->ai_addrlen) != -1) { + return; + } + } + throw std::runtime_error(get_errno_error()); +} + +void connect_socket(const int sock, const addrinfo* const info) { + if (connect(sock, info->ai_addr, info->ai_addrlen) == -1) { + throw std::runtime_error(get_errno_error()); + } +} + +void nonblock_socket(const int sock) { + if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) { + throw std::runtime_error(get_errno_error()); + } +} + +void* get_info_address(sockaddr& info) noexcept { + if (info.sa_family == AF_INET) { + return &(reinterpret_cast<sockaddr_in*>(&info)->sin_addr); + } + return &(reinterpret_cast<sockaddr_in6*>(&info)->sin6_addr); +} + +void listen_socket(const int sock) { + fcntl(sock, F_SETFL, O_NONBLOCK); + if (listen(sock, SOMAXCONN) == -1) { + throw std::runtime_error(get_errno_error()); + } +} + +// Returns std::nullopt on failure! We lose the ability to throw here. +std::optional<accept_ret> get_accept(const int sock) { + accept_ret info; + socklen_t size = sizeof(info.storage); + info.socket = + accept(sock, reinterpret_cast<sockaddr*>(&info.storage), &size); + if (info.socket == -1) { + return std::nullopt; + } + return info; +} + +void close_socket(const int sock) { + if (close(sock) == -1) { + throw std::runtime_error(get_errno_error()); + } +} + +// Returns the size of the receive buffer. +// For reliable, returns size of the stream (thanks [][][]). +// For unreliable, returns size of the next datagram available for reading. +std::size_t get_backlog_size(const int sock) { + size_t result = 0; + if (ioctl(sock, FIONREAD, &result) == -1) { + throw std::runtime_error(get_errno_error()); + } + return result; +} + +std::string get_socket_host_address(const int sock) { + sockaddr_in sin; + socklen_t size = sizeof(sin); + if (getsockname(sock, reinterpret_cast<sockaddr*>(&sin), &size) == -1) { + throw std::runtime_error(get_errno_error()); + } + return std::string(inet_ntoa(sin.sin_addr)); +} + +std::string get_socket_host_port(const int sock) { + sockaddr_in sin; + socklen_t size = sizeof(sin); + if (getsockname(sock, reinterpret_cast<sockaddr*>(&sin), &size) == -1) { + throw std::runtime_error(get_errno_error()); + } + return std::to_string(ntohs(sin.sin_port)); +} + +std::string get_socket_peer_address(const int sock) { + sockaddr_in sin; + socklen_t size = sizeof(sin); + if (getpeername(sock, reinterpret_cast<sockaddr*>(&sin), &size) == -1) { + throw std::runtime_error(get_errno_error()); + } + return std::string(inet_ntoa(sin.sin_addr)); +} + +std::string get_socket_peer_port(const int sock) { + sockaddr_in sin; + socklen_t size = sizeof(sin); + if (getpeername(sock, reinterpret_cast<sockaddr*>(&sin), &size) == -1) { + throw std::runtime_error(get_errno_error()); + } + return std::to_string(ntohs(sin.sin_port)); +} + +} // namespace net +} // namespace shared |
