Skip to content
Snippets Groups Projects
sockaddr.cpp 4.51 KiB
Newer Older
  • Learn to ignore specific revisions
  • Daniel Müller's avatar
    Daniel Müller committed
    #include "sockaddr.hpp"
    
    #include <cstring>
    #include <stdexcept>
    
    #include <arpa/inet.h>
    
    
    using namespace netlib;
    
    
    Daniel Müller's avatar
    Daniel Müller committed
    SockAddr::SockAddr()
        : SockAddr{IpAddr::V4("0.0.0.0"), 0}
    { }
    
    SockAddr::SockAddr(IpAddr _address, uint16_t _port)
        : address{_address}, port{_port}
    {
        setRawSockaddr(address, port);
    }
    
    SockAddr::SockAddr(const std::string &_address, uint16_t _port)
        : SockAddr(IpAddr(_address), _port)
    { }
    
    SockAddr::SockAddr(const std::string &_address_port)
    {
        std::string str_addr;
        std::string str_port;
    
        // Try to find the positions of the brackets and colons
        size_t pos_bracket1 = _address_port.find("[");
        size_t pos_bracket2 = _address_port.find("]:");
        size_t pos_colon = _address_port.find(":");
    
        // If no colon was found at all, the port is definitely missing
        if (pos_colon == std::string::npos)
        {
            throw std::runtime_error("SockAddr ip:port string is missing \":port\"");
        }
    
        // If the string starts with "[" and also contains "]:", it must be Ipv6
        if (pos_bracket1 == 0 && pos_bracket2 != std::string::npos)
        {
            str_addr = _address_port.substr(1, pos_bracket2-1);
            str_port = _address_port.substr(pos_bracket2+2);
            
            address = IpAddr::V6(str_addr);
        }
        // If the string contains "." it must be Ipv4
        else if (_address_port.find(".") != std::string::npos)
        {
            str_addr = _address_port.substr(0, pos_colon);
            str_port = _address_port.substr(pos_colon+1);
            
            address = IpAddr::V4(str_addr);
        }
        // If it is neither Ipv4 nor Ipv6, it is invalid
        else
        {
            throw std::runtime_error("Conversion from String to SockAddr failed");
        }
    
        // Convert the port string to int
        int port_int = std::stoi(str_port);
        // If the port is not in the range of uint16_t, it is invalid
        if (port_int < 0 || port_int > 0xffff || str_port.empty())
            throw std::runtime_error("Invalid port number");
    
        port = port_int;
    
        // Transfer the information onto the raw sockaddr
        setRawSockaddr(address, port);
    }
    
    SockAddr::SockAddr(sockaddr *_raw_sockaddr, IpAddr::Type _type)
    {
    
        if (_type == IpAddr::Type::V4)
        {
            // Type-pun the sockaddr to Ipv4 sockaddr_in
            raw_sockaddr.v4 = *((sockaddr_in*)_raw_sockaddr);
    
            // Get the port in host byte order
            port = ntohs(raw_sockaddr.v4.sin_port);
    
            // Set the address type
            address.type = _type;
            // Copy the raw address data
            address.raw_addr.v4 = raw_sockaddr.v4.sin_addr;
    
            // Buffer to hold the string representation of the Ipv4 address
            char str_addr[INET_ADDRSTRLEN];
    
            // Convert the raw address to string
            inet_ntop(AF_INET, &raw_sockaddr.v4.sin_addr, str_addr, INET_ADDRSTRLEN);
    
            // Set the string in address
            address.str_addr = str_addr;
        }
        else if (_type == IpAddr::Type::V6)
        {
            // Same as if the type was Ipv4, but with a 6 instead
    
            raw_sockaddr.v6 = *((sockaddr_in6*)_raw_sockaddr);
    
            port = ntohs(raw_sockaddr.v6.sin6_port);
    
            address.type = _type;
            address.raw_addr.v6 = raw_sockaddr.v6.sin6_addr;
    
            char str_addr[INET6_ADDRSTRLEN] = {0};
    
            inet_ntop(AF_INET6, &raw_sockaddr.v6.sin6_addr, str_addr, INET6_ADDRSTRLEN);
    
            address.str_addr = str_addr;
        }
        else
        {
            throw std::runtime_error("Can't build SockAddr from IpAddr::Type::Undef");
        }
    
    }
    
    void SockAddr::setRawSockaddr(IpAddr _address, uint16_t _port)
    {
        memset(&raw_sockaddr, 0, sizeof(raw_sockaddr));
    
        // Set the information in the raw sockaddr
        if (_address.isIpv4())
        {
            // Set address family to Ipv4
            raw_sockaddr.v4.sin_family = AF_INET;
            // Set the port (in network byte order)
            raw_sockaddr.v4.sin_port = htons(_port);
            // Copy the raw ip address from IpAddr
            raw_sockaddr.v4.sin_addr = _address.raw_addr.v4;
        }
        else if (_address.isIpv6())
        {
            // Set address family to Ipv6
            raw_sockaddr.v6.sin6_family = AF_INET6;
            // Set the port (in network byte order)
            raw_sockaddr.v6.sin6_port = htons(_port);
            // Copy the raw ip address from IpAddr
            raw_sockaddr.v6.sin6_addr = _address.raw_addr.v6;
        }
        else
        {
            throw std::runtime_error("Can't create SockAddr from IpAddr::Type::Undef");
        }
    }
    
    const IpAddr & SockAddr::getIpAddress() const
    {
        return address;
    }
    
    const std::string & SockAddr::getIpAddressString() const
    {
        return address.getAddressString();
    }
    
    const uint16_t SockAddr::getPort() const
    {
        return port;
    }