diff --git a/.clang-tidy b/.clang-tidy index 2f1538a..14aa108 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -7,6 +7,7 @@ Checks: " -cppcoreguidelines-avoid-magic-numbers, -cppcoreguidelines-non-private-member-variables-in-classes, -cppcoreguidelines-missing-std-forward, + -cppcoreguidelines-pro-type-vararg, " WarningsAsErrors: true HeaderFilterRegex: ".*" diff --git a/include/runtime/cfdp_runtime/socket.hpp b/include/runtime/cfdp_runtime/socket.hpp new file mode 100644 index 0000000..665eb98 --- /dev/null +++ b/include/runtime/cfdp_runtime/socket.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include +#include + +#include +#include +#include + +namespace cfdp::runtime::sockets +{ +enum class SocketType +{ + TCP = SOCK_STREAM, + UDP = SOCK_DGRAM, +}; + +class Socket +{ + public: + Socket(SocketType sType, uint16_t port, const std::string& ipAddr); + + int handle; + sockaddr_in addr{}; +}; + +class UDPClient +{ + public: + UDPClient(uint16_t port = 8000, const std::string& ipAddr = "127.0.0.1") + : socket(SocketType::UDP, port, ipAddr) + {} + + void sendMessage(std::vector message); + + private: + Socket socket; +}; + +class UDPServer +{ + public: + UDPServer(uint16_t port = 8000, const std::string& ipAddr = "0.0.0.0") + : socket(SocketType::UDP, port, ipAddr) + {} + + void socketBind(); + + private: + Socket socket; +}; +} // namespace cfdp::runtime::sockets diff --git a/include/runtime/cfdp_runtime/transport_interface.hpp b/include/runtime/cfdp_runtime/transport_interface.hpp new file mode 100644 index 0000000..b550e28 --- /dev/null +++ b/include/runtime/cfdp_runtime/transport_interface.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace cfdp::runtime::transport +{ +} diff --git a/src/cfdp_runtime/socket.cpp b/src/cfdp_runtime/socket.cpp new file mode 100644 index 0000000..330a28f --- /dev/null +++ b/src/cfdp_runtime/socket.cpp @@ -0,0 +1,77 @@ +#include +#include + +#include + +#include +#include +#include + +namespace +{ +// IP converter related retcodes. +constexpr int invalid_addr_in_addr_family = 0; + +// File descriptor related retcodes. +constexpr int file_descriptor_error = -1; + +// Socket related retcodes. +constexpr int socket_error = -1; +} // namespace + +cfdp::runtime::sockets::Socket::Socket(SocketType sType, uint16_t port, const std::string& ipAddr) + : handle(socket(AF_INET, utils::toUnderlying(sType), 0)) +{ + if (handle == socket_error) + { + throw std::runtime_error{"Could not create a socket."}; + } + + addr.sin_family = AF_INET; + addr.sin_port = port; + + auto result = inet_pton(AF_INET, ipAddr.c_str(), &addr.sin_addr); + + if (result == invalid_addr_in_addr_family) + { + throw std::runtime_error{"Could not parse passed IP address."}; + } + + auto currentFlags = fcntl(handle, F_GETFL); + + if (currentFlags == file_descriptor_error) + { + throw std::runtime_error{"Could not fetch file descriptor flags."}; + } + + auto status = fcntl(handle, F_SETFL, currentFlags | O_NONBLOCK); + + if (status == file_descriptor_error) + { + throw std::runtime_error{"Could not set the socket to non-blocking."}; + } +} + +void cfdp::runtime::sockets::UDPClient::sendMessage(std::vector message) +{ + auto length = message.size(); + auto addr = std::bit_cast(&socket.addr); + + auto result = sendto(socket.handle, message.data(), length, 0, addr, sizeof(socket.addr)); + + if (result == socket_error) + { + throw std::runtime_error{"Could not send data via socket."}; + } +} + +void cfdp::runtime::sockets::UDPServer::socketBind() +{ + auto addr = std::bit_cast(&socket.addr); + auto result = bind(socket.handle, addr, sizeof(socket.addr)); + + if (result == socket_error) + { + throw std::runtime_error{"Could not bind the socket."}; + } +}