diff --git a/Net/include/Poco/Net/IPAddress.h b/Net/include/Poco/Net/IPAddress.h index 8dc290c65..2ae11628a 100644 --- a/Net/include/Poco/Net/IPAddress.h +++ b/Net/include/Poco/Net/IPAddress.h @@ -61,9 +61,9 @@ public: enum Family /// Possible address families for IP addresses. { - IPv4 = Poco::Net::Impl::IPAddressImpl::IPv4 + IPv4 = Poco::Net::Impl::IPAddressImpl::IPv4, #ifdef POCO_HAVE_IPv6 - ,IPv6 = Poco::Net::Impl::IPAddressImpl::IPv6 + IPv6 = Poco::Net::Impl::IPAddressImpl::IPv6 #endif }; diff --git a/Net/include/Poco/Net/IPAddressImpl.h b/Net/include/Poco/Net/IPAddressImpl.h index eb90b8e56..64587d2cf 100644 --- a/Net/include/Poco/Net/IPAddressImpl.h +++ b/Net/include/Poco/Net/IPAddressImpl.h @@ -42,9 +42,9 @@ public: enum Family /// Possible address families for IP addresses. { - IPv4 + IPv4, #ifdef POCO_HAVE_IPv6 - ,IPv6 + IPv6 #endif }; diff --git a/Net/include/Poco/Net/SocketAddress.h b/Net/include/Poco/Net/SocketAddress.h index ee1029ed4..e47f091bc 100644 --- a/Net/include/Poco/Net/SocketAddress.h +++ b/Net/include/Poco/Net/SocketAddress.h @@ -43,6 +43,18 @@ class Net_API SocketAddress /// host address and a port number. { public: + enum Family + /// Possible address families for socket addresses. + { + IPv4 = Poco::Net::Impl::SocketAddressImpl::IPv4, +#ifdef POCO_HAVE_IPv6 + IPv6 = Poco::Net::Impl::SocketAddressImpl::IPv6, +#endif +#ifdef POCO_OS_FAMILY_UNIX + UNIX_LOCAL = Poco::Net::Impl::SocketAddressImpl::UNIX_LOCAL +#endif + }; + SocketAddress(); /// Creates a wildcard (all zero) IPv4 SocketAddress. @@ -80,6 +92,13 @@ public: /// [::ffff:192.168.1.120]:2040 /// www.appinf.com:8080 + SocketAddress(Family family, const std::string& addr); + /// Creates a SocketAddress of the given family from a + /// string representation of the address, which is + /// either an IP address and port number, separated by + /// a colon for IPv4 or IPv6 addresses, or a path for + /// UNIX_LOCAL sockets. + SocketAddress(const SocketAddress& addr); /// Creates a SocketAddress by copying another one. @@ -110,7 +129,7 @@ public: std::string toString() const; /// Returns a string representation of the address. - IPAddress::Family family() const; + Family family() const; /// Returns the address family of the host's address. bool operator < (const SocketAddress& socketAddress) const; @@ -131,6 +150,8 @@ public: protected: void init(const IPAddress& hostAddress, Poco::UInt16 portNumber); void init(const std::string& hostAddress, Poco::UInt16 portNumber); + void init(Family family, const std::string& address); + void init(const std::string& hostAndPort); Poco::UInt16 resolveService(const std::string& service); private: @@ -144,14 +165,18 @@ private: Ptr pImpl() const; void newIPv4(); - void newIPv4(const sockaddr_in*); - void newIPv4(const IPAddress& hostAddress, Poco::UInt16 portNumber); - + +#if defined(POCO_HAVE_IPv6) void newIPv6(const sockaddr_in6*); - void newIPv6(const IPAddress& hostAddress, Poco::UInt16 portNumber); +#endif + +#if defined(POCO_OS_FAMILY_UNIX) + void newLocal(const sockaddr_un* sockAddr); + void newLocal(const std::string& path); +#endif void destruct(); @@ -168,7 +193,11 @@ private: AlignerType aligner; } #else // !POCO_ENABLE_CPP11 - AlignedCharArrayUnion + #if defined(POCO_HAVE_IPv6) + AlignedCharArrayUnion + #else + AlignedCharArrayUnion + #endif #endif // POCO_ENABLE_CPP11 _memory; #else // !POCO_HAVE_ALIGNMENT @@ -231,7 +260,7 @@ inline void SocketAddress::newIPv4(const IPAddress& hostAddress, Poco::UInt16 po } - +#if defined(POCO_HAVE_IPv6) inline void SocketAddress::newIPv6(const sockaddr_in6* sockAddr) { #ifdef POCO_HAVE_ALIGNMENT @@ -240,7 +269,7 @@ inline void SocketAddress::newIPv6(const sockaddr_in6* sockAddr) _pImpl = new Poco::Net::Impl::IPv6SocketAddressImpl(sockAddr); #endif } - + inline void SocketAddress::newIPv6(const IPAddress& hostAddress, Poco::UInt16 portNumber) { @@ -250,14 +279,31 @@ inline void SocketAddress::newIPv6(const IPAddress& hostAddress, Poco::UInt16 po _pImpl = new Poco::Net::Impl::IPv6SocketAddressImpl(hostAddress.addr(), htons(portNumber), hostAddress.scope()); #endif } +#endif // POCO_HAVE_IPv6 -inline IPAddress::Family SocketAddress::family() const +#if defined(POCO_OS_FAMILY_UNIX) +inline void SocketAddress::newLocal(const sockaddr_un* sockAddr) { - return host().family(); +#ifdef POCO_HAVE_ALIGNMENT + new (storage()) Poco::Net::Impl::LocalSocketAddressImpl(sockAddr); +#else + _pImpl = new Poco::Net::Impl::LocalSocketAddressImpl(sockAddr); +#endif } +inline void SocketAddress::newLocal(const std::string& path) +{ +#ifdef POCO_HAVE_ALIGNMENT + new (storage()) Poco::Net::Impl::LocalSocketAddressImpl(path.c_str()); +#else + _pImpl = new Poco::Net::Impl::LocalSocketAddressImpl(path.c_str()); +#endif +} +#endif // POCO_OS_FAMILY_UNIX + + #ifdef POCO_HAVE_ALIGNMENT inline char* SocketAddress::storage() { @@ -266,15 +312,20 @@ inline char* SocketAddress::storage() #endif -inline bool SocketAddress::operator == (const SocketAddress& socketAddress) const +inline bool SocketAddress::operator == (const SocketAddress& socketAddress) const { - return host() == socketAddress.host() && port() == socketAddress.port(); +#if defined(POCO_OS_FAMILY_UNIX) + if (family() == UNIX_LOCAL) + return host() == socketAddress.host() && port() == socketAddress.port(); + else +#endif + return toString() == socketAddress.toString(); } inline bool SocketAddress::operator != (const SocketAddress& socketAddress) const { - return host() != socketAddress.host() || port() != socketAddress.port(); + return !operator == (socketAddress); } diff --git a/Net/include/Poco/Net/SocketAddressImpl.h b/Net/include/Poco/Net/SocketAddressImpl.h index 40835d2eb..01a52eb22 100644 --- a/Net/include/Poco/Net/SocketAddressImpl.h +++ b/Net/include/Poco/Net/SocketAddressImpl.h @@ -38,6 +38,18 @@ class Net_API SocketAddressImpl #endif { public: + enum Family + /// Possible address families for socket addresses. + { + IPv4, +#ifdef POCO_HAVE_IPv6 + IPv6, +#endif +#ifdef POCO_OS_FAMILY_UNIX + UNIX_LOCAL +#endif + }; + virtual ~SocketAddressImpl(); virtual IPAddress host() const = 0; @@ -45,6 +57,8 @@ public: virtual poco_socklen_t length() const = 0; virtual const struct sockaddr* addr() const = 0; virtual int af() const = 0; + virtual Family family() const = 0; + virtual std::string toString() const = 0; protected: SocketAddressImpl(); @@ -59,20 +73,15 @@ class Net_API IPv4SocketAddressImpl: public SocketAddressImpl { public: IPv4SocketAddressImpl(); - IPv4SocketAddressImpl(const struct sockaddr_in* addr); - IPv4SocketAddressImpl(const void* addr, UInt16 port); - IPAddress host() const; - UInt16 port() const; - poco_socklen_t length() const; - const struct sockaddr* addr() const; - int af() const; + Family family() const; + std::string toString() const; private: struct sockaddr_in _addr; @@ -113,6 +122,12 @@ inline int IPv4SocketAddressImpl::af() const } +inline SocketAddressImpl::Family IPv4SocketAddressImpl::family() const +{ + return SocketAddressImpl::IPv4; +} + + #if defined(POCO_HAVE_IPv6) @@ -120,20 +135,15 @@ class Net_API IPv6SocketAddressImpl: public SocketAddressImpl { public: IPv6SocketAddressImpl(const struct sockaddr_in6* addr); - IPv6SocketAddressImpl(const void* addr, UInt16 port); - IPv6SocketAddressImpl(const void* addr, UInt16 port, UInt32 scope); - IPAddress host() const; - UInt16 port() const; - poco_socklen_t length() const; - const struct sockaddr* addr() const; - - int af() const; + int af() const; + Family family() const; + std::string toString() const; private: struct sockaddr_in6 _addr; @@ -174,7 +184,87 @@ inline int IPv6SocketAddressImpl::af() const } -#endif //POCO_HAVE_IPv6 +inline SocketAddressImpl::Family IPv6SocketAddressImpl::family() const +{ + return SocketAddressImpl::IPv6; +} + + +#endif // POCO_HAVE_IPv6 + + +#if defined(POCO_OS_FAMILY_UNIX) + + +class Net_API LocalSocketAddressImpl: public SocketAddressImpl +{ +public: + LocalSocketAddressImpl(const struct sockaddr_un* addr); + LocalSocketAddressImpl(const char* path); + ~LocalSocketAddressImpl(); + IPAddress host() const; + UInt16 port() const; + poco_socklen_t length() const; + const struct sockaddr* addr() const; + int af() const; + Family family() const; + const char* path() const; + std::string toString() const; + +private: + struct sockaddr_un* _pAddr; + // Note: We allocate struct sockaddr_un on the heap, otherwise we would + // waste a lot of memory due to small object optimization in SocketAddress. +}; + + +// +// inlines +// + +inline IPAddress LocalSocketAddressImpl::host() const +{ + throw Poco::InvalidAccessException("local socket address does not have host IP address"); +} + + +inline UInt16 LocalSocketAddressImpl::port() const +{ + throw Poco::InvalidAccessException("local socket address does not have port number"); +} + + +inline poco_socklen_t LocalSocketAddressImpl::length() const +{ + return sizeof(struct sockaddr_un); +} + + +inline const struct sockaddr* LocalSocketAddressImpl::addr() const +{ + return reinterpret_cast(_pAddr); +} + + +inline int LocalSocketAddressImpl::af() const +{ + return _pAddr->sun_family; +} + + +inline SocketAddressImpl::Family LocalSocketAddressImpl::family() const +{ + return SocketAddressImpl::UNIX_LOCAL; +} + + +inline const char* LocalSocketAddressImpl::path() const +{ + return _pAddr->sun_path; +} + + +#endif // POCO_OS_FAMILY_UNIX } } } // namespace Poco::Net::Impl diff --git a/Net/include/Poco/Net/SocketDefs.h b/Net/include/Poco/Net/SocketDefs.h index e7583a0b7..ccc91fa16 100644 --- a/Net/include/Poco/Net/SocketDefs.h +++ b/Net/include/Poco/Net/SocketDefs.h @@ -134,6 +134,7 @@ #include #include #include + #include #include #if POCO_OS != POCO_OS_HPUX #include @@ -271,15 +272,19 @@ #if defined(POCO_HAVE_SALEN) - #define poco_set_sa_len(pSA, len) (pSA)->sa_len = (len) - #define poco_set_sin_len(pSA) (pSA)->sin_len = sizeof(struct sockaddr_in) + #define poco_set_sa_len(pSA, len) (pSA)->sa_len = (len) + #define poco_set_sin_len(pSA) (pSA)->sin_len = sizeof(struct sockaddr_in) #if defined(POCO_HAVE_IPv6) #define poco_set_sin6_len(pSA) (pSA)->sin6_len = sizeof(struct sockaddr_in6) #endif + #if defined(POCO_OS_FAMILY_UNIX) + #define poco_set_sun_len(pSA, len) (pSA)->sun_len = (len) + #endif #else - #define poco_set_sa_len(pSA, len) (void) 0 - #define poco_set_sin_len(pSA) (void) 0 - #define poco_set_sin6_len(pSA) (void) 0 + #define poco_set_sa_len(pSA, len) (void) 0 + #define poco_set_sin_len(pSA) (void) 0 + #define poco_set_sin6_len(pSA) (void) 0 + #define poco_set_sun_len(pSA, len) (void) 0 #endif diff --git a/Net/src/MulticastSocket.cpp b/Net/src/MulticastSocket.cpp index 6bd388ccd..e14f8ffb4 100644 --- a/Net/src/MulticastSocket.cpp +++ b/Net/src/MulticastSocket.cpp @@ -82,12 +82,12 @@ MulticastSocket& MulticastSocket::operator = (const Socket& socket) void MulticastSocket::setInterface(const NetworkInterface& interfc) { - if (address().family() == IPAddress::IPv4) + if (address().family() == SocketAddress::IPv4) { impl()->setOption(IPPROTO_IP, IP_MULTICAST_IF, interfc.firstAddress(IPAddress::IPv4)); } #if defined(POCO_HAVE_IPv6) - else if (address().family() == IPAddress::IPv6) + else if (address().family() == SocketAddress::IPv6) { impl()->setOption(IPPROTO_IPV6, IPV6_MULTICAST_IF, interfc.index()); } diff --git a/Net/src/SocketAddress.cpp b/Net/src/SocketAddress.cpp index cf2721d74..2b9bf26d8 100644 --- a/Net/src/SocketAddress.cpp +++ b/Net/src/SocketAddress.cpp @@ -20,7 +20,6 @@ #include "Poco/Net/DNS.h" #include "Poco/RefCountedObject.h" #include "Poco/NumberParser.h" -#include "Poco/NumberFormatter.h" #include "Poco/BinaryReader.h" #include "Poco/BinaryWriter.h" #include @@ -29,12 +28,16 @@ using Poco::RefCountedObject; using Poco::NumberParser; -using Poco::NumberFormatter; using Poco::UInt16; using Poco::InvalidArgumentException; using Poco::Net::Impl::SocketAddressImpl; using Poco::Net::Impl::IPv4SocketAddressImpl; +#ifdef POCO_HAVE_IPv6 using Poco::Net::Impl::IPv6SocketAddressImpl; +#endif +#ifdef POCO_OS_FAMILY_UNIX +using Poco::Net::Impl::LocalSocketAddressImpl; +#endif namespace Poco { @@ -85,41 +88,30 @@ SocketAddress::SocketAddress(const std::string& hostAddress, const std::string& } +SocketAddress::SocketAddress(Family family, const std::string& addr) +{ + init(family, addr); +} + + SocketAddress::SocketAddress(const std::string& hostAndPort) { - poco_assert (!hostAndPort.empty()); - - std::string host; - std::string port; - std::string::const_iterator it = hostAndPort.begin(); - std::string::const_iterator end = hostAndPort.end(); - if (*it == '[') - { - ++it; - while (it != end && *it != ']') host += *it++; - if (it == end) throw InvalidArgumentException("Malformed IPv6 address"); - ++it; - } - else - { - while (it != end && *it != ':') host += *it++; - } - if (it != end && *it == ':') - { - ++it; - while (it != end) port += *it++; - } - else throw InvalidArgumentException("Missing port number"); - init(host, resolveService(port)); + init(hostAndPort); } SocketAddress::SocketAddress(const SocketAddress& socketAddress) { - if (socketAddress.family() == IPAddress::IPv4) + if (socketAddress.family() == IPv4) newIPv4(reinterpret_cast(socketAddress.addr())); - else +#if defined(POCO_HAVE_IPv6) + else if (socketAddress.family() == IPv6) newIPv6(reinterpret_cast(socketAddress.addr())); +#endif +#if defined(POCO_OS_FAMILY_UNIX) + else if (socketAddress.family() == UNIX_LOCAL) + newLocal(reinterpret_cast(socketAddress.addr())); +#endif } @@ -130,6 +122,10 @@ SocketAddress::SocketAddress(const struct sockaddr* sockAddr, poco_socklen_t len #if defined(POCO_HAVE_IPv6) else if (length == sizeof(struct sockaddr_in6)) newIPv6(reinterpret_cast(sockAddr)); +#endif +#if defined(POCO_OS_FAMILY_UNIX) + else if (length > 0 && length <= sizeof(struct sockaddr_un) && sockAddr->sa_family == AF_UNIX) + newLocal(reinterpret_cast(sockAddr)); #endif else throw Poco::InvalidArgumentException("Invalid address length passed to SocketAddress()"); } @@ -145,6 +141,9 @@ bool SocketAddress::operator < (const SocketAddress& socketAddress) const { if (family() < socketAddress.family()) return true; if (family() > socketAddress.family()) return false; +#if defined(POCO_OS_FAMILY_UNIX) + if (family() == UNIX_LOCAL) return toString() < socketAddress.toString(); +#endif if (host() < socketAddress.host()) return true; if (host() > socketAddress.host()) return false; return (port() < socketAddress.port()); @@ -156,10 +155,16 @@ SocketAddress& SocketAddress::operator = (const SocketAddress& socketAddress) if (&socketAddress != this) { destruct(); - if (socketAddress.family() == IPAddress::IPv4) + if (socketAddress.family() == IPv4) newIPv4(reinterpret_cast(socketAddress.addr())); - else +#if defined(POCO_HAVE_IPv6) + else if (socketAddress.family() == IPv6) newIPv6(reinterpret_cast(socketAddress.addr())); +#endif +#if defined(POCO_OS_FAMILY_UNIX) + else if (socketAddress.family() == UNIX_LOCAL) + newLocal(reinterpret_cast(socketAddress.addr())); +#endif } return *this; } @@ -195,19 +200,15 @@ int SocketAddress::af() const } +SocketAddress::Family SocketAddress::family() const +{ + return static_cast(pImpl()->family()); +} + + std::string SocketAddress::toString() const { - std::string result; -#if defined(POCO_HAVE_IPv6) - if (host().family() == IPAddress::IPv6) - result.append("["); - result.append(host().toString()); - if (host().family() == IPAddress::IPv6) - result.append("]"); -#endif - result.append(":"); - NumberFormatter::append(result, port()); - return result; + return pImpl()->toString(); } @@ -247,6 +248,46 @@ void SocketAddress::init(const std::string& hostAddress, Poco::UInt16 portNumber } +void SocketAddress::init(Family family, const std::string& address) +{ + if (family == UNIX_LOCAL) + { + newLocal(address); + } + else + { + init(address); + } +} + + +void SocketAddress::init(const std::string& hostAndPort) +{ + std::string host; + std::string port; + std::string::const_iterator it = hostAndPort.begin(); + std::string::const_iterator end = hostAndPort.end(); + if (*it == '[') + { + ++it; + while (it != end && *it != ']') host += *it++; + if (it == end) throw InvalidArgumentException("Malformed IPv6 address"); + ++it; + } + else + { + while (it != end && *it != ':') host += *it++; + } + if (it != end && *it == ':') + { + ++it; + while (it != end) port += *it++; + } + else throw InvalidArgumentException("Missing port number"); + init(host, resolveService(port)); +} + + Poco::UInt16 SocketAddress::resolveService(const std::string& service) { unsigned port; diff --git a/Net/src/SocketAddressImpl.cpp b/Net/src/SocketAddressImpl.cpp index f2de61b46..9cb60bb06 100644 --- a/Net/src/SocketAddressImpl.cpp +++ b/Net/src/SocketAddressImpl.cpp @@ -16,6 +16,7 @@ #include "Poco/Net/SocketAddressImpl.h" #include "Poco/Net/SocketDefs.h" +#include "Poco/NumberFormatter.h" #include @@ -23,6 +24,7 @@ namespace Poco { namespace Net { namespace Impl { + // // SocketAddressImpl // @@ -66,6 +68,16 @@ IPv4SocketAddressImpl::IPv4SocketAddressImpl(const void* addr, UInt16 port) } +std::string IPv4SocketAddressImpl::toString() const +{ + std::string result; + result.append(host().toString()); + result.append(":"); + NumberFormatter::append(result, port()); + return result; +} + + #if defined(POCO_HAVE_IPv6) @@ -101,7 +113,59 @@ IPv6SocketAddressImpl::IPv6SocketAddressImpl(const void* addr, UInt16 port, UInt } +std::string IPv6SocketAddressImpl::toString() const +{ + std::string result; + result.append("["); + result.append(host().toString()); + result.append("]"); + result.append(":"); + NumberFormatter::append(result, port()); + return result; +} + + #endif // POCO_HAVE_IPv6 +#if defined(POCO_OS_FAMILY_UNIX) + + +// +// LocalSocketAddressImpl +// + + +LocalSocketAddressImpl::LocalSocketAddressImpl(const struct sockaddr_un* addr) +{ + _pAddr = new sockaddr_un; + std::memcpy(_pAddr, addr, sizeof(struct sockaddr_un)); +} + + +LocalSocketAddressImpl::LocalSocketAddressImpl(const char* path) +{ + _pAddr = new sockaddr_un; + poco_set_sun_len(_pAddr, std::strlen(path) + sizeof(struct sockaddr_un) - sizeof(_pAddr->sun_path) + 1); + _pAddr->sun_family = AF_UNIX; + std::strcpy(_pAddr->sun_path, path); +} + + +LocalSocketAddressImpl::~LocalSocketAddressImpl() +{ + delete _pAddr; +} + + +std::string LocalSocketAddressImpl::toString() const +{ + std::string result(path()); + return result; +} + + +#endif // POCO_OS_FAMILY_UNIX + + } } } // namespace Poco::Net::Impl diff --git a/Net/src/SocketImpl.cpp b/Net/src/SocketImpl.cpp index 14d872bf3..5c33434f4 100644 --- a/Net/src/SocketImpl.cpp +++ b/Net/src/SocketImpl.cpp @@ -212,7 +212,7 @@ void SocketImpl::bind(const SocketAddress& address, bool reuseAddress) void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only) { #if defined(POCO_HAVE_IPv6) - if (address.family() != IPAddress::IPv6) + if (address.family() != SocketAddress::IPv6) throw Poco::InvalidArgumentException("SocketAddress must be an IPv6 address"); if (_sockfd == POCO_INVALID_SOCKET)