mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			426 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			426 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * SRT - Secure, Reliable, Transport
 | |
|  * Copyright (c) 2018 Haivision Systems Inc.
 | |
|  * 
 | |
|  * This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | |
|  * 
 | |
|  */
 | |
| 
 | |
| /*****************************************************************************
 | |
| written by
 | |
|    Haivision Systems Inc.
 | |
|  *****************************************************************************/
 | |
| 
 | |
| #ifndef INC_SRT_NETINET_ANY_H
 | |
| #define INC_SRT_NETINET_ANY_H
 | |
| 
 | |
| #include <cstring> // memcmp
 | |
| #include <string>
 | |
| #include <sstream>
 | |
| #include "platform_sys.h"
 | |
| 
 | |
| // This structure should replace every use of sockaddr and its currently
 | |
| // used specializations, sockaddr_in and sockaddr_in6. This is to simplify
 | |
| // the use of the original BSD API that relies on type-violating type casts.
 | |
| // You can use the instances of sockaddr_any in every place where sockaddr is
 | |
| // required.
 | |
| 
 | |
| namespace srt
 | |
| {
 | |
| 
 | |
| struct sockaddr_any
 | |
| {
 | |
|     union
 | |
|     {
 | |
|         sockaddr_in sin;
 | |
|         sockaddr_in6 sin6;
 | |
|         sockaddr sa;
 | |
|     };
 | |
| 
 | |
|     // The type is intended to be the same as the length
 | |
|     // parameter in ::accept, ::bind and ::connect functions.
 | |
| 
 | |
|     // This is the type used by SRT.
 | |
|     typedef int len_t;
 | |
| 
 | |
|     // This is the type used by system functions
 | |
| #ifdef _WIN32
 | |
|     typedef int syslen_t;
 | |
| #else
 | |
|     typedef socklen_t syslen_t;
 | |
| #endif
 | |
| 
 | |
|     // Note: by having `len_t` type here the usage in
 | |
|     // API functions is here limited to SRT. For system
 | |
|     // functions you can pass the address here as (socklen_t*)&sa.len,
 | |
|     // but just do it on your own risk, as there's no guarantee
 | |
|     // that sizes of `int` and `socklen_t` do not differ. The safest
 | |
|     // way seems to be using an intermediate proxy to be written
 | |
|     // back here from the value of `syslen_t`.
 | |
|     len_t len;
 | |
| 
 | |
|     struct SysLenWrapper
 | |
|     {
 | |
|         syslen_t syslen;
 | |
|         len_t& backwriter;
 | |
|         syslen_t* operator&() { return &syslen; }
 | |
| 
 | |
|         SysLenWrapper(len_t& source): syslen(source), backwriter(source)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         ~SysLenWrapper()
 | |
|         {
 | |
|             backwriter = syslen;
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     // Usage:
 | |
|     //    ::accept(lsn_sock, sa.get(), &sa.syslen());
 | |
|     SysLenWrapper syslen()
 | |
|     {
 | |
|         return SysLenWrapper(len);
 | |
|     }
 | |
| 
 | |
|     static size_t storage_size()
 | |
|     {
 | |
|         typedef union
 | |
|         {
 | |
|             sockaddr_in sin;
 | |
|             sockaddr_in6 sin6;
 | |
|             sockaddr sa;
 | |
|         } ucopy;
 | |
|         return sizeof (ucopy);
 | |
|     }
 | |
| 
 | |
|     void reset()
 | |
|     {
 | |
|         // sin6 is the largest field
 | |
|         memset((&sin6), 0, sizeof sin6);
 | |
|         len = 0;
 | |
|     }
 | |
| 
 | |
|     // Default domain is unspecified, and
 | |
|     // in this case the size is 0.
 | |
|     // Note that AF_* (and alias PF_*) types have
 | |
|     // many various values, of which only
 | |
|     // AF_INET and AF_INET6 are handled here.
 | |
|     // Others make the same effect as unspecified.
 | |
|     explicit sockaddr_any(int domain = AF_UNSPEC)
 | |
|     {
 | |
|         // Default domain is "unspecified", 0
 | |
|         reset();
 | |
| 
 | |
|         // Overriding family as required in the parameters
 | |
|         // and the size then accordingly.
 | |
|         sa.sa_family = domain == AF_INET || domain == AF_INET6 ? domain : AF_UNSPEC;
 | |
|         switch (domain)
 | |
|         {
 | |
|         case AF_INET:
 | |
|             len = len_t(sizeof (sockaddr_in));
 | |
|             break;
 | |
| 
 | |
|             // Use size of sin6 as the default size
 | |
|             // len must be properly set so that the
 | |
|             // family-less sockaddr is passed to bind/accept
 | |
|         default:
 | |
|             len = len_t(sizeof (sockaddr_in6));
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     sockaddr_any(const sockaddr_storage& stor)
 | |
|     {
 | |
|         // Here the length isn't passed, so just rely on family.
 | |
|         set((const sockaddr*)&stor);
 | |
|     }
 | |
| 
 | |
|     sockaddr_any(const sockaddr* source, len_t namelen = 0)
 | |
|     {
 | |
|         if (namelen == 0)
 | |
|             set(source);
 | |
|         else
 | |
|             set(source, namelen);
 | |
|     }
 | |
| 
 | |
|     void set(const sockaddr* source)
 | |
|     {
 | |
|         // Less safe version, simply trust the caller that the
 | |
|         // memory at 'source' is also large enough to contain
 | |
|         // all data required for particular family.
 | |
|         if (source->sa_family == AF_INET)
 | |
|         {
 | |
|             memcpy((&sin), source, sizeof sin);
 | |
|             len = sizeof sin;
 | |
|         }
 | |
|         else if (source->sa_family == AF_INET6)
 | |
|         {
 | |
|             memcpy((&sin6), source, sizeof sin6);
 | |
|             len = sizeof sin6;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             // Error fallback: no other families than IP are regarded.
 | |
|             // Note: socket set up this way isn't intended to be used
 | |
|             // for bind/accept.
 | |
|             sa.sa_family = AF_UNSPEC;
 | |
|             len = 0;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void set(const sockaddr* source, syslen_t namelen)
 | |
|     {
 | |
|         // It's not safe to copy it directly, so check.
 | |
|         if (source->sa_family == AF_INET && namelen >= syslen_t(sizeof sin))
 | |
|         {
 | |
|             memcpy((&sin), source, sizeof sin);
 | |
|             len = sizeof sin;
 | |
|         }
 | |
|         else if (source->sa_family == AF_INET6 && namelen >= syslen_t(sizeof sin6))
 | |
|         {
 | |
|             // Note: this isn't too safe, may crash for stupid values
 | |
|             // of source->sa_family or any other data
 | |
|             // in the source structure, so make sure it's correct first.
 | |
|             memcpy((&sin6), source, sizeof sin6);
 | |
|             len = sizeof sin6;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             reset();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void set(const sockaddr_in& in4)
 | |
|     {
 | |
|         memcpy((&sin), &in4, sizeof in4);
 | |
|         len = sizeof in4;
 | |
|     }
 | |
| 
 | |
|     void set(const sockaddr_in6& in6)
 | |
|     {
 | |
|         memcpy((&sin6), &in6, sizeof in6);
 | |
|         len = sizeof in6;
 | |
|     }
 | |
| 
 | |
|     sockaddr_any(const in_addr& i4_adr, uint16_t port)
 | |
|     {
 | |
|         // Some cases require separately IPv4 address passed as in_addr,
 | |
|         // so port is given separately.
 | |
|         sa.sa_family = AF_INET;
 | |
|         sin.sin_addr = i4_adr;
 | |
|         sin.sin_port = htons(port);
 | |
|         len = sizeof sin;
 | |
|     }
 | |
| 
 | |
|     sockaddr_any(const in6_addr& i6_adr, uint16_t port)
 | |
|     {
 | |
|         sa.sa_family = AF_INET6;
 | |
|         sin6.sin6_addr = i6_adr;
 | |
|         sin6.sin6_port = htons(port);
 | |
|         len = sizeof sin6;
 | |
|     }
 | |
| 
 | |
|     static len_t size(int family)
 | |
|     {
 | |
|         switch (family)
 | |
|         {
 | |
|         case AF_INET:
 | |
|             return len_t(sizeof (sockaddr_in));
 | |
| 
 | |
|         case AF_INET6:
 | |
|             return len_t(sizeof (sockaddr_in6));
 | |
| 
 | |
|         default:
 | |
|             return 0; // fallback
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     bool empty() const
 | |
|     {
 | |
|         bool isempty = true;  // unspec-family address is always empty
 | |
| 
 | |
|         if (sa.sa_family == AF_INET)
 | |
|         {
 | |
|             isempty = (sin.sin_port == 0
 | |
|                     && sin.sin_addr.s_addr == 0);
 | |
|         }
 | |
|         else if (sa.sa_family == AF_INET6)
 | |
|         {
 | |
|             isempty = (sin6.sin6_port == 0
 | |
|                     && memcmp(&sin6.sin6_addr, &in6addr_any, sizeof in6addr_any) == 0);
 | |
|         }
 | |
|         // otherwise isempty stays with default false
 | |
|         return isempty;
 | |
|     }
 | |
| 
 | |
|     len_t size() const
 | |
|     {
 | |
|         return size(sa.sa_family);
 | |
|     }
 | |
| 
 | |
|     int family() const { return sa.sa_family; }
 | |
|     void family(int val)
 | |
|     {
 | |
|         sa.sa_family = val;
 | |
|         len = size();
 | |
|     }
 | |
| 
 | |
|     // port is in exactly the same location in both sin and sin6
 | |
|     // and has the same size. This is actually yet another common
 | |
|     // field, just not mentioned in the sockaddr structure.
 | |
|     uint16_t& r_port() { return sin.sin_port; }
 | |
|     uint16_t r_port() const { return sin.sin_port; }
 | |
|     int hport() const { return ntohs(sin.sin_port); }
 | |
| 
 | |
|     void hport(int value)
 | |
|     {
 | |
|         // Port is fortunately located at the same position
 | |
|         // in both sockaddr_in and sockaddr_in6 and has the
 | |
|         // same size.
 | |
|         sin.sin_port = htons(value);
 | |
|     }
 | |
| 
 | |
|     sockaddr* get() { return &sa; }
 | |
|     const sockaddr* get() const { return &sa; }
 | |
| 
 | |
|     // Sometimes you need to get the address
 | |
|     // the way suitable for e.g. inet_ntop.
 | |
|     const void* get_addr() const
 | |
|     {
 | |
|         if (sa.sa_family == AF_INET)
 | |
|             return &sin.sin_addr.s_addr;
 | |
| 
 | |
|         if (sa.sa_family == AF_INET6)
 | |
|             return &sin6.sin6_addr;
 | |
| 
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     void* get_addr()
 | |
|     {
 | |
|         const sockaddr_any* that = this;
 | |
|         return (void*)that->get_addr();
 | |
|     }
 | |
| 
 | |
|     template <int> struct TypeMap;
 | |
| 
 | |
|     template <int af_domain>
 | |
|     typename TypeMap<af_domain>::type& get();
 | |
| 
 | |
|     struct Equal
 | |
|     {
 | |
|         bool operator()(const sockaddr_any& c1, const sockaddr_any& c2)
 | |
|         {
 | |
|             if (c1.family() != c2.family())
 | |
|                 return false;
 | |
| 
 | |
|             // Cannot use memcmp due to having in some systems
 | |
|             // another field like sockaddr_in::sin_len. This exists
 | |
|             // in some BSD-derived systems, but is not required by POSIX.
 | |
|             // Therefore sockaddr_any class cannot operate with it,
 | |
|             // as in this situation it would be safest to state that
 | |
|             // particular implementations may have additional fields
 | |
|             // of different purpose beside those required by POSIX.
 | |
|             //
 | |
|             // The only reliable way to compare two underlying sockaddr
 | |
|             // object is then to compare the port value and the address
 | |
|             // value.
 | |
|             //
 | |
|             // Fortunately the port is 16-bit and located at the same
 | |
|             // offset in both sockaddr_in and sockaddr_in6.
 | |
| 
 | |
|             return c1.sin.sin_port == c2.sin.sin_port
 | |
|                 && c1.equal_address(c2);
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     struct EqualAddress
 | |
|     {
 | |
|         bool operator()(const sockaddr_any& c1, const sockaddr_any& c2)
 | |
|         {
 | |
|             if ( c1.sa.sa_family == AF_INET )
 | |
|             {
 | |
|                 return c1.sin.sin_addr.s_addr == c2.sin.sin_addr.s_addr;
 | |
|             }
 | |
| 
 | |
|             if ( c1.sa.sa_family == AF_INET6 )
 | |
|             {
 | |
|                 return memcmp(&c1.sin6.sin6_addr, &c2.sin6.sin6_addr, sizeof (in6_addr)) == 0;
 | |
|             }
 | |
| 
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|     };
 | |
| 
 | |
|     bool equal_address(const sockaddr_any& rhs) const
 | |
|     {
 | |
|         return EqualAddress()(*this, rhs);
 | |
|     }
 | |
| 
 | |
|     struct Less
 | |
|     {
 | |
|         bool operator()(const sockaddr_any& c1, const sockaddr_any& c2)
 | |
|         {
 | |
|             return memcmp(&c1, &c2, sizeof(c1)) < 0;
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     // Tests if the current address is the "any" wildcard.
 | |
|     bool isany() const
 | |
|     {
 | |
|         if (sa.sa_family == AF_INET)
 | |
|             return sin.sin_addr.s_addr == INADDR_ANY;
 | |
| 
 | |
|         if (sa.sa_family == AF_INET6)
 | |
|             return memcmp(&sin6.sin6_addr, &in6addr_any, sizeof in6addr_any) == 0;
 | |
| 
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // Debug support
 | |
|     std::string str() const
 | |
|     {
 | |
|         if (family() != AF_INET && family() != AF_INET6)
 | |
|             return "unknown:0";
 | |
| 
 | |
|         std::ostringstream output;
 | |
|         char hostbuf[1024];
 | |
|         int flags;
 | |
| 
 | |
|     #if ENABLE_GETNAMEINFO
 | |
|         flags = NI_NAMEREQD;
 | |
|     #else
 | |
|         flags = NI_NUMERICHOST | NI_NUMERICSERV;
 | |
|     #endif
 | |
| 
 | |
|         if (!getnameinfo(get(), size(), hostbuf, 1024, NULL, 0, flags))
 | |
|         {
 | |
|             output << hostbuf;
 | |
|         }
 | |
| 
 | |
|         output << ":" << hport();
 | |
|         return output.str();
 | |
|     }
 | |
| 
 | |
|     bool operator==(const sockaddr_any& other) const
 | |
|     {
 | |
|         return Equal()(*this, other);
 | |
|     }
 | |
| 
 | |
|     bool operator!=(const sockaddr_any& other) const { return !(*this == other); }
 | |
| };
 | |
| 
 | |
| template<> struct sockaddr_any::TypeMap<AF_INET> { typedef sockaddr_in type; };
 | |
| template<> struct sockaddr_any::TypeMap<AF_INET6> { typedef sockaddr_in6 type; };
 | |
| 
 | |
| template <>
 | |
| inline sockaddr_any::TypeMap<AF_INET>::type& sockaddr_any::get<AF_INET>() { return sin; }
 | |
| template <>
 | |
| inline sockaddr_any::TypeMap<AF_INET6>::type& sockaddr_any::get<AF_INET6>() { return sin6; }
 | |
| 
 | |
| } // namespace srt
 | |
| 
 | |
| #endif
 |