diff --git a/example/unix_dgram_example.cpp b/example/unix_dgram_example.cpp new file mode 100644 index 0000000..3180f52 --- /dev/null +++ b/example/unix_dgram_example.cpp @@ -0,0 +1,54 @@ +#include "../include/socketwrapper/unixdgram.hpp" +#include +#include +#include + +int main(int argc, char** argv) +{ + if (argc <= 1) + return 0; + + if (strcmp(argv[1], "r") == 0) + { + std::cout << "--- Receiver ---\n"; + + auto sock = net::unix_dgram_socket(net::endpoint_unix("/tmp/sock2")); + + auto buffer = std::array{}; + const auto [bytes_read, peer] = sock.read(net::span(buffer)); + std::cout << "Peer addr: " << peer.get_addr_string() + << "; Bytes read: " << bytes_read << '\n'; + std::cout << std::string_view(buffer.data(), bytes_read) << '\n'; + + const auto read_result = sock.read(net::span{buffer}, std::chrono::milliseconds(4000)); + if (read_result.has_value()) + { + const auto& [bytes_read, peer_opt] = read_result.value(); + std::cout << "Peer addr: " << peer_opt.get_addr_string() + << "; Bytes read: " << bytes_read << '\n'; + std::cout << std::string_view{buffer.data(), bytes_read} << '\n'; + } + else + { + std::cout << "No message received :(\n"; + } + } + else if (strcmp(argv[1], "s") == 0) + { + std::cout << "--- Sender ---\n"; + + auto sock = net::unix_dgram_socket(); + + auto buffer = std::string{"Hello world"}; + const auto endpoint = net::endpoint_unix("/tmp/sock2"); + sock.send(endpoint, net::span(buffer)); + std::cout << "All messages sent." << std::endl; + + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + + auto vec = std::vector{'A', 'B', 'C'}; + sock.send(endpoint, net::span(vec)); + sock.send(endpoint, net::span("KekWWW")); + std::cout << "All messages sent. Again." << std::endl; + } +} diff --git a/example/unix_stream_example.cpp b/example/unix_stream_example.cpp new file mode 100644 index 0000000..9a275b3 --- /dev/null +++ b/example/unix_stream_example.cpp @@ -0,0 +1,63 @@ +#include "../include/socketwrapper/unixstream.hpp" + +#include +#include +#include + +int main(int argc, char** argv) +{ + if (argc <= 1) + return 0; + + if (strcmp(argv[1], "r") == 0) + { + std::cout << "--- Receiver ---\n"; + + auto buffer = std::array{}; + auto acceptor = net::unix_stream_acceptor(net::endpoint_unix("/tmp/sock1")); + + std::cout << "Waiting for accept\n"; + auto opt = acceptor.accept(std::chrono::milliseconds(5000)); + if (!opt) + { + std::cout << "No acception\n"; + return 0; + } + const auto& sock = opt.value(); + std::cout << "Accepted\n"; + + std::cout << "Wait for data ...\n"; + size_t bytes_read = sock.read(net::span{buffer}); + std::cout << "Received: " << bytes_read << " - " << std::string_view{buffer.data(), bytes_read} << '\n'; + + const auto read_result = sock.read(net::span{buffer}, std::chrono::milliseconds(4000)); + if (read_result.has_value()) + { + std::cout << "Received: " << *read_result << " - " << std::string_view{buffer.data(), *read_result} << '\n'; + } + } + else if (strcmp(argv[1], "s") == 0) + { + std::cout << "--- Sender ---\n"; + + auto sock = net::unix_stream_connection(); + std::cout << "Socket created\n"; + + sock.connect(net::endpoint_unix("/tmp/sock1")); + std::cout << "Connected\n"; + + std::this_thread::sleep_for(std::chrono::milliseconds(3000)); + + auto vec = std::vector{'H', 'e', 'l', 'l', 'o'}; + // sock.send(net::span{vec}); + // sock.send(net::span{std::string {"Hello World"}}); + sock.send(net::span{vec.begin(), vec.end()}); + std::cout << "Sent\n"; + + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + + auto buffer_view = std::string_view{"Hello String_view-World"}; + sock.send(net::span{buffer_view.begin(), buffer_view.end()}); + std::cout << "Sent again\n"; + } +} diff --git a/include/socketwrapper/detail/utility.hpp b/include/socketwrapper/detail/utility.hpp index d620684..92c4708 100644 --- a/include/socketwrapper/detail/utility.hpp +++ b/include/socketwrapper/detail/utility.hpp @@ -20,7 +20,8 @@ namespace net { enum class ip_version : uint8_t { v4 = AF_INET, - v6 = AF_INET6 + v6 = AF_INET6, + unixsock = AF_UNIX }; enum class socket_type : uint8_t diff --git a/include/socketwrapper/endpoint.hpp b/include/socketwrapper/endpoint.hpp index b87864b..1b632de 100644 --- a/include/socketwrapper/endpoint.hpp +++ b/include/socketwrapper/endpoint.hpp @@ -6,7 +6,9 @@ #include #include #include +#include #include +#include namespace net { @@ -114,6 +116,11 @@ class endpoint m_up_to_date = false; return reinterpret_cast(m_addr); } + + inline bool is_valid_addr_size(size_t s) + { + return s == addr_size; + } }; /// Template specialization for ip v6 connections @@ -216,11 +223,76 @@ class endpoint m_up_to_date = false; return reinterpret_cast(m_addr); } + + inline bool is_valid_addr_size(size_t s) + { + return s == addr_size; + } +}; + + +/// Template specialization for unix connections +template <> +class endpoint +{ + sockaddr_un m_addr; + +public: + using addr_type = sockaddr_un; + static constexpr const size_t addr_size = sizeof(sockaddr_un); + static constexpr const size_t addr_str_len = sizeof(sockaddr_un::sun_path); + static constexpr const int addr_family = AF_UNIX; + + endpoint() = default; + + explicit endpoint(const sockaddr_un& addr) + : m_addr(addr) + { + + } + + explicit endpoint(const char* path) + { + int n = strlen(path); + if(n >= (int)addr_str_len - 1) + throw std::invalid_argument("path is too long"); + m_addr.sun_family = AF_UNIX; + std::memcpy(m_addr.sun_path, path, n); + } + + std::string get_addr_string() const + { + return std::string(m_addr.sun_path); + } + + std::array get_addr_bytes() const + { + auto bytes = std::array{}; + std::copy_n(m_addr.sun_path, addr_str_len, bytes.data()); + return bytes; + } + + + const sockaddr& get_addr() const + { + return reinterpret_cast(m_addr); + } + + sockaddr& get_addr() + { + return reinterpret_cast(m_addr); + } + + inline bool is_valid_addr_size(size_t s) + { + return s <= addr_size; + } }; /// Shorthand using-declarations for endpoint class template specializations using endpoint_v4 = endpoint; using endpoint_v6 = endpoint; +using endpoint_unix = endpoint; } // namespace net diff --git a/include/socketwrapper/tcp.hpp b/include/socketwrapper/tcp.hpp index 8f92705..d424854 100644 --- a/include/socketwrapper/tcp.hpp +++ b/include/socketwrapper/tcp.hpp @@ -333,8 +333,8 @@ class tcp_acceptor : public detail::base_socket { auto client_addr = endpoint(); socklen_t addr_len = client_addr.addr_size; - if (const int sock = ::accept(fd, &(client_addr.get_addr()), &addr_len); - sock > 0 && addr_len == client_addr.addr_size) + const int sock = ::accept(fd, &(client_addr.get_addr()), &addr_len); + if (sock > 0 && client_addr.is_valid_addr_size(addr_len)) { return std::move(tcp_connection{sock, client_addr}); } diff --git a/include/socketwrapper/unixdgram.hpp b/include/socketwrapper/unixdgram.hpp new file mode 100644 index 0000000..7bf7a9c --- /dev/null +++ b/include/socketwrapper/unixdgram.hpp @@ -0,0 +1,12 @@ +#ifndef SOCKETWRAPPER_NET_UNIXDGRAM_HPP +#define SOCKETWRAPPER_NET_UNIXDGRAM_HPP + +#include "udp.hpp" + +namespace net { + +using unix_dgram_socket = udp_socket; + +} // namespace net + +#endif diff --git a/include/socketwrapper/unixstream.hpp b/include/socketwrapper/unixstream.hpp new file mode 100644 index 0000000..c6c025d --- /dev/null +++ b/include/socketwrapper/unixstream.hpp @@ -0,0 +1,13 @@ +#ifndef SOCKETWRAPPER_NET_UNIXSTREAM_HPP +#define SOCKETWRAPPER_NET_UNIXSTREAM_HPP + +#include "tcp.hpp" + +namespace net { + +using unix_stream_connection = tcp_connection; +using unix_stream_acceptor = tcp_acceptor; + +} // namespace net + +#endif