aboutsummaryrefslogtreecommitdiff
path: root/comp3331/server/src/shared/net.hh
diff options
context:
space:
mode:
Diffstat (limited to 'comp3331/server/src/shared/net.hh')
-rw-r--r--comp3331/server/src/shared/net.hh87
1 files changed, 87 insertions, 0 deletions
diff --git a/comp3331/server/src/shared/net.hh b/comp3331/server/src/shared/net.hh
new file mode 100644
index 0000000..b17ca1f
--- /dev/null
+++ b/comp3331/server/src/shared/net.hh
@@ -0,0 +1,87 @@
+#ifndef SHARED_NET_HH_
+#define SHARED_NET_HH_
+
+#include <algorithm>
+#include <arpa/inet.h>
+#include <chrono>
+#include <cstdint>
+#include <cstring>
+#include <errno.h>
+#include <fcntl.h>
+#include <memory>
+#include <netdb.h>
+#include <optional>
+#include <stdexcept>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <thread>
+#include <type_traits>
+#include <unistd.h>
+#include <unordered_map>
+#include <vector>
+
+#include "shared/shared.hh"
+
+// Functions in this namespace are common network-related wrappers with error
+// checking.
+namespace shared {
+
+using addrinfo_t = std::shared_ptr<addrinfo>; // for automatic freeaddrinfo call
+addrinfo_t make_addrinfo(const char* const address, const char* const port,
+ const addrinfo&& hints);
+
+using socket_t = int;
+int make_socket(const addrinfo_t& info);
+int accept_socket(const socket_t& sock);
+void bind_socket(const socket_t sock, const addrinfo_t& info);
+void connect_socket(const socket_t sock, const addrinfo_t& info);
+void listen_socket(const socket_t sock);
+void close_socket(const socket_t sock);
+
+struct header {
+ std::uint32_t size = 0; // size of packet, including header.
+ std::uint32_t sequence; // sequence number of packet
+ char command[3]; // command type, if \0\0\0 then it's an ack
+};
+static_assert(std::is_trivially_copyable<header>::value,
+ "header must be memcpy-able");
+struct packet {
+ header header;
+ std::vector<char> contents;
+};
+
+// Our packets contents consist of data entries like so:
+// std::uint32_t | char[] | DATA
+// ^ size of data ^ name ^ data, which repeats for size length
+// Any packet may contain multiple, or zero, entries. The name can be any
+// length. This way we don't have to define structs with hardcoded length
+// limits, and we can use this format when sending anything, even files.
+// Numeric values will be encoded as strings and converted when necessary.
+using contents_t = std::unordered_map<std::string, std::string>;
+void send_packet(const packet& packet, const socket_t& sock,
+ const sockaddr_in& dest);
+void send_packet(const packet& packet, const socket_t& sock);
+
+packet contents_to_packet(const contents_t& contents,
+ const char* const command);
+contents_t packet_to_contents(const packet& packet);
+
+// Recv's sockets, might return nullptr if no packet available.
+struct recv_packet_ret {
+ sockaddr_in origin;
+ struct packet packet;
+};
+
+// non-blocking
+std::shared_ptr<recv_packet_ret> maybe_urecv_packet(const socket_t& sock);
+// blocking, will throw if timeout is elapsed
+std::shared_ptr<recv_packet_ret> urecv_packet(const socket_t& rsock,
+ const bool& timeout = true);
+std::shared_ptr<packet> rrecv_packet(const socket_t& rsock,
+ const bool& timeout = true);
+
+} // namespace shared
+
+#endif