// // socketstream.cpp // libscio // // Created by Bob Polis at 2020-03-02 // Copyright (c) 2020 SwiftCoder. All rights reserved. // #include "libscio.hpp" #include #include #include #include #include #include #include #include using namespace sc::io; socketstream::socketstream(int domain, int type) : std::iostream(&_iobuf), _domain(domain), _type(type) { _iobuf.fd(::socket(_domain, _type, 0)); throw_if_min1_msg(_iobuf.fd(), "could not create socket"); std::memset(&_sa, 0, sizeof(struct sockaddr_storage)); } socketstream::socketstream() : std::iostream(&_iobuf) { std::memset(&_sa, 0, sizeof(struct sockaddr_storage)); } socketstream::socketstream(socketstream&& other) : std::iostream(&_iobuf) { _iobuf.fd(other._iobuf.fd()); _domain = other._domain; _type = other._type; std::memcpy(&_sa, &other._sa, sizeof(struct sockaddr_storage)); other._iobuf.fd(-1); std::memset(&other._sa, 0, sizeof(struct sockaddr_storage)); } socketstream& socketstream::operator=(socketstream&& other) { if (this != &other) { _iobuf.fd(other._iobuf.fd()); _domain = other._domain; _type = other._type; std::memcpy(&_sa, &other._sa, sizeof(struct sockaddr_storage)); other._iobuf.fd(-1); std::memset(&other._sa, 0, sizeof(struct sockaddr_storage)); } return *this; } socketstream::~socketstream() { close(); } void socketstream::close() { if (_iobuf.fd() != -1) { ::close(_iobuf.fd()); _iobuf.fd(-1); } } 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(_iobuf.fd(), addr, addr_sz)); if (_type == SOCK_STREAM) { throw_if_min1(::listen(_iobuf.fd(), SOMAXCONN)); } } socketstream socketstream::accept() const { socketstream peer; socklen_t len = sizeof(struct sockaddr_storage); int active_socket = ::accept(_iobuf.fd(), reinterpret_cast(&peer._sa), &len); throw_if_min1(active_socket); peer._iobuf.fd(active_socket); peer._domain = _domain; peer._type = _type; peer._iobuf.fd(active_socket); return peer; } void socketstream::connect(const socket_address& host) { endpoint_from_address(host, &_sa); struct sockaddr* addr = reinterpret_cast(&_sa); throw_if_min1(::connect(_iobuf.fd(), addr, sizeof(_sa))); } std::string socketstream::address() const { const struct sockaddr* addr = reinterpret_cast(&_sa); socket_address sa = address_from_endpoint(addr); return sa.address; } 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"); } } 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; }