aboutsummaryrefslogtreecommitdiff
path: root/src/shared/net/net.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/net/net.cc')
-rw-r--r--src/shared/net/net.cc138
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