diff --git a/libscio.hpp b/libscio.hpp index 6aab244..1fb14f3 100644 --- a/libscio.hpp +++ b/libscio.hpp @@ -89,7 +89,7 @@ namespace sc { class socketstream : public fdstream { public: - socketstream() = default; + socketstream(); socketstream(int domain, int type); // copying forbidden @@ -104,7 +104,7 @@ namespace sc { virtual ~socketstream(); // server - void make_server(const socket_address& address) const; + void make_server(const socket_address& sa); socketstream accept() const; // client @@ -112,16 +112,17 @@ namespace sc { // convenience: human-readable addresses std::string address() const; - std::string peer_address() const; // address/endpoint conversion methods - struct sockaddr endpoint_from_address(const socket_address& address) const; - socket_address address_from_endpoint(const struct sockaddr& endpoint) const; + void endpoint_from_address(const socket_address& address, + struct sockaddr_storage* endpoint) const; + socket_address address_from_endpoint(const struct sockaddr* endpoint) const; protected: int _socket {-1}; int _domain {0}; int _type {0}; + struct sockaddr_storage _sa; }; struct float_80 { diff --git a/socketstream.cpp b/socketstream.cpp index 849d6e4..b57960a 100644 --- a/socketstream.cpp +++ b/socketstream.cpp @@ -7,26 +7,38 @@ // #include "libscio.hpp" +#include #include +#include +#include +#include +#include +#include +#include using namespace sc::io; socketstream::socketstream(int domain, int type) : fdstream(), _domain(domain), _type(type) { _socket = socket(_domain, _type, 0); - if (_socket == -1) { - throw std::runtime_error("socketstream: could not create socket"); - } + throw_if_min1_msg(_socket, "could not create socket"); _inbuf.fd(_socket); _outbuf.fd(_socket); + std::memset(&_sa, 0, sizeof(struct sockaddr_storage)); +} + +socketstream::socketstream() : fdstream() { + std::memset(&_sa, 0, sizeof(struct sockaddr_storage)); } socketstream::socketstream(socketstream&& other) { _socket = other._socket; _domain = other._domain; _type = other._type; + std::memcpy(&_sa, &other._sa, sizeof(struct sockaddr_storage)); other._socket = -1; + std::memset(&other._sa, 0, sizeof(struct sockaddr_storage)); } socketstream& socketstream::operator=(socketstream&& other) { @@ -34,8 +46,10 @@ socketstream& socketstream::operator=(socketstream&& other) { _socket = other._socket; _domain = other._domain; _type = other._type; + std::memcpy(&_sa, &other._sa, sizeof(struct sockaddr_storage)); other._socket = -1; + std::memset(&other._sa, 0, sizeof(struct sockaddr_storage)); } return *this; } @@ -46,41 +60,133 @@ socketstream::~socketstream() { } } -void socketstream::make_server(const socket_address& address) const { - // build sockaddr - // bind - // if stream: listen +void socketstream::make_server(const socket_address& sa) { + size_t addr_sz = 0; + switch (_domain) { + case AF_UNIX: { + struct sockaddr_un* sau = reinterpret_cast(&_sa); + sau->sun_family = AF_UNIX; + addr_sz = sa.address.size(); + std::strncpy(sau->sun_path, sa.address.c_str(), addr_sz); + break; + } + case AF_INET: { + struct sockaddr_in* sa4 = reinterpret_cast(&_sa); + sa4->sin_family = AF_INET; + sa4->sin_addr.s_addr = INADDR_ANY; + sa4->sin_port = htons(sa.port); + addr_sz = sizeof(struct sockaddr_in); + break; + } + case AF_INET6: { + struct sockaddr_in6* sa6 = reinterpret_cast(&_sa); + sa6->sin6_family = AF_INET6; + sa6->sin6_addr = in6addr_any; + sa6->sin6_port = htons(sa.port); + addr_sz = sizeof(struct sockaddr_in6); + break; + } + default: + errno = EAFNOSUPPORT; + throw_if_min1_msg(-1, "unsupported socket domain"); + } + struct sockaddr* addr = reinterpret_cast(&_sa); + throw_if_min1(::bind(_socket, addr, addr_sz)); + if (_type == SOCK_STREAM) { + throw_if_min1(::listen(_socket, SOMAXCONN)); + } } socketstream socketstream::accept() const { - int passive_socket = ::accept(_socket, nullptr, 0); - if (passive_socket == -1) { - throw std::runtime_error("socketstream: could not accept"); - } socketstream peer; - peer._socket = passive_socket; + socklen_t len = sizeof(struct sockaddr_storage); + int active_socket = ::accept(_socket, + reinterpret_cast(&peer._sa), + &len); + throw_if_min1(active_socket); + peer._socket = active_socket; peer._domain = _domain; peer._type = _type; return peer; } void socketstream::connect(const socket_address& host) { - // build sockaddr - // connect + endpoint_from_address(host, &_sa); + struct sockaddr* addr = reinterpret_cast(&_sa); + throw_if_min1(::connect(_socket, addr, sizeof(_sa))); } std::string socketstream::address() const { - return ""; // TODO + const struct sockaddr* addr = reinterpret_cast(&_sa); + socket_address sa = address_from_endpoint(addr); + return sa.address; } -std::string socketstream::peer_address() const { - return ""; // TODO +void socketstream::endpoint_from_address(const socket_address& address, + struct sockaddr_storage* endpoint) const { + throw_if_null(endpoint); + switch (_domain) { + case AF_UNIX: { + struct sockaddr_un* addr = reinterpret_cast(endpoint); + addr->sun_family = AF_UNIX; + std::memcpy(addr->sun_path, address.address.c_str(), address.address.size()); + break; + } + case AF_INET: { + struct sockaddr_in* addr = reinterpret_cast(endpoint); + addr->sin_family = AF_INET; + addr->sin_port = htons(address.port); + ::inet_pton(_domain, address.address.c_str(), &addr->sin_addr); + break; + } + case AF_INET6: { + struct sockaddr_in6* addr = reinterpret_cast(endpoint); + addr->sin6_family = AF_INET6; + addr->sin6_port = htons(address.port); + addr->sin6_flowinfo = 0; + ::inet_pton(_domain, address.address.c_str(), &addr->sin6_addr); + addr->sin6_scope_id = 0; + break; + } + default: + errno = EAFNOSUPPORT; + throw_if_min1_msg(-1, "unsupported socket domain"); + } } -struct sockaddr socketstream::endpoint_from_address(const socket_address& address) const { - -} - -socket_address socketstream::address_from_endpoint(const struct sockaddr& endpoint) const { - +socket_address socketstream::address_from_endpoint(const struct sockaddr* endpoint) const { + throw_if_null(endpoint); + socket_address sa; + switch (_domain) { + case AF_UNIX: { + const struct sockaddr_un* addr = reinterpret_cast(endpoint); + sa.address = addr->sun_path; + sa.port = 0; + break; + } + case AF_INET: { + const struct sockaddr_in* addr = reinterpret_cast(endpoint); + std::vector buf; + buf.resize(INET_ADDRSTRLEN); + ::inet_ntop(_domain, &addr->sin_addr, buf.data(), buf.size()); + std::string temp {buf.data(), buf.size()}; + sa.address = std::move(temp); + sa.port = ntohs(addr->sin_port); + break; + } + case AF_INET6: { + const struct sockaddr_in6* addr = reinterpret_cast(endpoint); + std::vector buf; + buf.resize(INET6_ADDRSTRLEN); + ::inet_ntop(_domain, &addr->sin6_addr, buf.data(), buf.size()); + std::string temp {buf.data(), buf.size()}; + sa.address = std::move(temp); + sa.port = ntohs(addr->sin6_port); + break; + } + default: + errno = EAFNOSUPPORT; + throw_if_min1_msg(-1, "unsupported socket domain"); + } + return sa; }