#ifndef NETADR_H
#define NETADR_H
#ifdef _WIN32
#pragma once
#endif
#include <tier0/basetypes.h>
#include <tier0/dbg.h>
#undef SetPort
const int k_ncchMaxNetAdrString = 48;
typedef enum : unsigned short
{
k_EIPTypeInvalid = 0,
k_EIPTypeLoopbackDeprecated,
k_EIPTypeBroadcastDeprecated,
k_EIPTypeV4,
k_EIPTypeV6,
} ipadrtype_t;
#define NETADR_DEFINED
#pragma pack(push,1)
extern const byte k_ipv6Bytes_LinkLocalAllNodes[16];
extern const byte k_ipv6Bytes_Loopback[16];
extern const byte k_ipv6Bytes_Any[16];
class CIPAddress
{
public:
inline CIPAddress() { Clear(); }
explicit CIPAddress( uint unIP ) { Clear(); SetIPv4( unIP ); }
explicit CIPAddress( const char *pch ) { Clear(); SetFromString( pch ); }
void Clear() {
memset( m_rgubIPv6, 0, sizeof( m_rgubIPv6 ) );
m_unIPv6Scope = 0;
m_usType = k_EIPTypeV4;
}
ipadrtype_t GetType() const { return ipadrtype_t( m_usType ); }
void SetType( ipadrtype_t type );
void SetIPv4(uint unIP);
void SetIP( const CIPAddress that ) { *this = that; }
void SetIPv4(uint8 b1, uint8 b2, uint8 b3, uint8 b4);
bool SetFromString( const char *psz, uint16 *punPort = nullptr );
void SetIPV4Broadcast() { SetIPv4( 0xffffffff ); }
void SetIPV6Broadcast( uint32 nScope = 0 ) { SetIPV6( k_ipv6Bytes_LinkLocalAllNodes, nScope ); }
void SetIPV4Loopback() { SetIPv4( 0x7f000001 ); }
void SetIPV6Loopback() { SetIPV6( k_ipv6Bytes_Loopback, 0 ); }
void SetIPV4Any() { SetIPv4( 0 ); }
void SetIPV6Any() { SetIPV6( k_ipv6Bytes_Any, 0 ); }
uint GetIPv4() const;
void GetIPV6( byte *result ) const;
const byte *GetIPV6Bytes() const;
void SetIPV6( const byte *bytes, uint32 nScope = 0 );
uint32 GetIPV6Scope() const;
void SetIPV6Scope( uint32 nScope );
bool IsMappedIPv4() const;
bool BConvertMappedToIPv4();
bool BConvertIPv4ToMapped();
void ToString( char *pchBuffer, uint32 unBufferSize, const uint16 *punPort = nullptr ) const;
template< size_t maxLenInChars >
char* ToString_safe( char (&pDest)[maxLenInChars], const uint16 *punPort = nullptr ) const
{
ToString( &pDest[0], maxLenInChars, punPort );
return pDest;
}
bool SetFromSockadr(const void *addr, size_t addr_size, uint16 *punPort = nullptr );
template <typename T> bool SetFromSockadr(const T *s, uint16 *punPort = nullptr ) { return SetFromSockadr( s, sizeof(*s), punPort ); }
bool HasIP() const;
bool IsLoopback() const;
bool IsReservedAdr() const;
bool IsBroadcast() const;
bool IsValid() const; bool SetFromSocket( int hSocket );
static CIPAddress CreateIPv4Loopback() { CIPAddress ret; ret.SetIPV4Loopback(); return ret; }
static CIPAddress CreateIPv6Loopback() { CIPAddress ret; ret.SetIPV6Loopback(); return ret; }
bool operator==(const CIPAddress &netadr) const;
bool operator!=(const CIPAddress &netadr) const;
bool operator<(const CIPAddress &netadr) const;
static unsigned int GetHashKey( const CIPAddress &netadr );
unsigned int GetIPHash() const { return GetHashKey( *this ); }
struct Hash
{
inline unsigned int operator()( const CIPAddress &x ) const
{
return CIPAddress::GetHashKey( x );
}
};
protected:
union {
uint m_unIPv4; struct
{
#ifdef VALVE_BIG_ENDIAN
uint8 b1, b2, b3, b4;
#else
uint8 b4, b3, b2, b1;
#endif
} m_IPv4Bytes;
byte m_rgubIPv6[16]; uint64 m_ipv6Qword[2]; };
uint32 m_unIPv6Scope; ipadrtype_t m_usType; };
COMPILE_TIME_ASSERT( sizeof(CIPAddress) == 22 );
class CIPAndPort : public CIPAddress
{
public:
inline CIPAndPort() : CIPAddress(), m_usPort( 0 ) { }
inline CIPAndPort( uint unIP, uint16 usPort ) : CIPAddress() { SetIPAndPort( unIP, usPort ); }
explicit CIPAndPort( uint unIP ) : CIPAddress( unIP ), m_usPort( 0 ) { }
explicit CIPAndPort( const char *pch ) : CIPAddress(), m_usPort( 0 ) { SetFromString( pch ); }
explicit CIPAndPort( const CIPAddress &that ) { *this = that; }
explicit CIPAndPort( const CIPAddress &that, uint16 usPort ) { *this = that; SetPort( usPort ); }
CIPAndPort operator=( const CIPAddress &that )
{
*static_cast<CIPAddress*>(this) = that;
return * this;
}
CIPAddress& GetIP() { return *this; }
const CIPAddress& GetIP() const { return *this; }
bool SetFromString( const char *psz )
{
return CIPAddress::SetFromString( psz, &m_usPort );
}
void SetPort( unsigned short port );
void SetIPAndPort( CIPAddress ipAddress, unsigned short usPort ) { *this = ipAddress; SetPort( usPort ); }
void SetIPAndPort( uint unIP, unsigned short usPort ) { SetIPv4( unIP ); SetPort( usPort ); }
void SetIPV6AndPort( const byte *bytes, uint16 nPort, uint32 nScope = 0 ) { SetIPV6( bytes, nScope ); SetPort( nPort ); }
bool CompareAdr(const CIPAndPort &a, bool onlyBase = false) const;
unsigned short GetPort() const { return m_usPort; }
bool HasPort() const;
bool IsValid() const;
void ToString( char *pchBuffer, uint32 unBufferSize, bool onlyBase = false ) const;
template< size_t maxLenInChars >
char* ToString_safe( char (&pDest)[maxLenInChars], bool onlyBase = false ) const
{
ToString( &pDest[0], maxLenInChars, onlyBase );
return pDest;
}
bool SetFromSockadr(const void *addr, size_t addr_size )
{
return CIPAddress::SetFromSockadr( addr, addr_size, &m_usPort );
}
template <typename T> bool SetFromSockadr(const T *s) { return SetFromSockadr( s, sizeof(*s) ); }
size_t ToSockadr(void *addr, size_t addr_size) const;
template <typename T> size_t ToSockadr(T *s) const { return ToSockadr( s, sizeof(*s) ); }
void ToSockadrIPV6(void *addr, size_t addr_size) const;
template <typename T> void ToSockadrIPV6(T *s) const { ToSockadrIPV6( s, sizeof(*s) ); }
bool SetFromSocket( int hSocket );
bool operator==(const CIPAndPort &netadr) const {return ( CompareAdr( netadr ) );}
bool operator!=(const CIPAndPort &netadr) const {return !( CompareAdr( netadr ) );}
bool operator<(const CIPAndPort &netadr) const;
static unsigned int GetHashKey( const CIPAndPort &netadr );
struct Hash
{
inline unsigned int operator()( const CIPAndPort &x ) const
{
return CIPAndPort::GetHashKey( x );
}
};
private:
unsigned short m_usPort = 0; };
#pragma pack(pop)
COMPILE_TIME_ASSERT( sizeof(CIPAndPort) == 24 );
using netadr_t = CIPAndPort;
class CUtlNetAdrRender
{
public:
CUtlNetAdrRender( const CIPAddress &obj )
{
obj.ToString_safe( m_rgchString );
}
CUtlNetAdrRender( const CIPAndPort &obj, bool bBaseOnly = false )
{
obj.ToString_safe( m_rgchString, bBaseOnly );
}
CUtlNetAdrRender( uint32 unIP )
{
CIPAndPort addr( unIP, 0 );
addr.ToString_safe( m_rgchString, true );
}
CUtlNetAdrRender( uint32 unIP, uint16 nPort )
{
CIPAndPort addr( unIP, nPort );
addr.ToString_safe( m_rgchString, false );
}
const char * String() const
{
return m_rgchString;
}
private:
char m_rgchString[k_ncchMaxNetAdrString];
};
inline void CIPAddress::SetIPv4(uint8 b1, uint8 b2, uint8 b3, uint8 b4)
{
m_usType = k_EIPTypeV4;
m_unIPv4 = ( b4 ) + ( b3 << 8 ) + ( b2 << 16 ) + ( b1 << 24 );
}
inline void CIPAddress::SetIPv4(uint unIP)
{
m_usType = k_EIPTypeV4;
m_unIPv4 = unIP;
}
inline void CIPAddress::SetType(ipadrtype_t newtype)
{
m_usType = newtype;
}
inline uint CIPAddress::GetIPv4() const
{
if ( m_usType != k_EIPTypeV6 )
return m_unIPv4;
AssertMsg( false, "CIPAndPort::GetIPv4 called on IPv6 address" );
return 0;
}
inline const byte *CIPAddress::GetIPV6Bytes() const
{
Assert( m_usType == k_EIPTypeV6 );
return m_rgubIPv6;
}
inline void CIPAddress::SetIPV6( const byte *bytes, uint32 nScope )
{
m_usType = k_EIPTypeV6;
memcpy( m_rgubIPv6, bytes, 16 );
m_unIPv6Scope = nScope;
}
inline uint32 CIPAddress::GetIPV6Scope() const
{
Assert( m_usType == k_EIPTypeV6 );
return m_unIPv6Scope;
}
inline void CIPAddress::SetIPV6Scope( uint32 nScope )
{
Assert( m_usType == k_EIPTypeV6 );
m_unIPv6Scope = nScope;
}
inline void CIPAndPort::SetPort(unsigned short newport)
{
m_usPort = newport;
}
#endif