1 //========= Copyright � Valve Corporation, All rights reserved. ============//
2 #ifndef NETADR_H
3 #define NETADR_H
4 #ifdef _WIN32
5 #pragma once
6 #endif
7 
8 #include <tier0/basetypes.h>
9 #include <tier0/dbg.h>
10 #undef SetPort
11 
12 // Max length of a netadr_t in string format (with port),
13 // including null
14 const int k_ncchMaxNetAdrString = 48;
15 
16 typedef enum
17 {
18 	// Reserved invalid/dummy address type
19 	NA_NULL = 0,
20 
21 	// Do not use this.  In some primordial code, "loopback" often actually meant "localhost",
22 	// and sometimes it meant "internal buffers, not actually using the network system at all."
23 	// We don't need the latter in Steam, and we don't need a separate address for the former (just
24 	// use the appropriate reserved address!)
25 	NA_LOOPBACK_DEPRECATED,
26 
27 	// Do not use this.  There are already reserved IP addresses to refer to this concept.
28 	// It is not a seperate address *type*.  In fact, there is an IPv4 broadcast addresses and an
29 	// IPv6 broadcast address, so it's not entirely clear exactly what this means.
30 	NA_BROADCAST_DEPRECATED,
31 
32 	NA_IP, // IPv4
33 	NA_IPV6,
34 } netadrtype_t;
35 
36 const netadrtype_t k_EIPTypeInvalid = NA_NULL;
37 const netadrtype_t k_EIPTypeV4 = NA_IP;
38 const netadrtype_t k_EIPTypeV6 = NA_IPV6;
39 
40 #define NETADR_DEFINED
41 #pragma pack(push,1)
42 
43 extern const byte k_ipv6Bytes_LinkLocalAllNodes[16];
44 extern const byte k_ipv6Bytes_Loopback[16];
45 extern const byte k_ipv6Bytes_Any[16];
46 
47 class netadr_t
48 {
49 public:
50 
51 	// NOTE: For historical reasons, the default constructor sets address type
52 	// to *NA_IP* (not NA_NULL!) but the IP and port are 0, so IsValid() will return false
netadr_t()53 	inline netadr_t() { memset((void *)this, 0, sizeof(*this) ); type = NA_IP; }
netadr_t(uint unIP,uint16 usPort)54 	inline netadr_t( uint unIP, uint16 usPort ) { memset((void *)this, 0, sizeof(*this) ); SetIPAndPort( unIP, usPort ); }
netadr_t(uint unIP)55 	explicit	netadr_t( uint unIP ) { memset((void *)this, 0, sizeof(*this) ); SetIPv4( unIP ); }
netadr_t(const char * pch)56 	explicit	netadr_t( const char *pch ) { memset((void *)this, 0, sizeof(*this) ); SetFromString( pch ); }
57 
58 	/// Set to invalid address (NA_NULL)
Clear()59 	void	Clear() { memset((void *)this, 0, sizeof(*this)); }
60 
61 	/// Get address type
GetType()62 	netadrtype_t GetType() const { return netadrtype_t( type ); }
63 
64 	/// Set address type without changing any other fields
65 	void	SetType( netadrtype_t type );
66 
67 	/// Set port, without changing address type or IP
68 	void	SetPort( unsigned short port );
69 
70 	/// Set IPv4 IP given host-byte order argument.
71 	/// Also slams the address type to NA_IP.  Port does not change
72 	void	SetIPv4(uint unIP);
73 
74 	/// Set IPv4 given individual address octets.
75 	/// Also slams the address type to NA_IP.  Port does not change
76 	void	SetIPv4(uint8 b1, uint8 b2, uint8 b3, uint8 b4);
77 
78 	/// Set IPv4 IP and port at the same time.  Also sets address type to NA_IP
SetIPAndPort(uint unIP,unsigned short usPort)79 	void    SetIPAndPort( uint unIP, unsigned short usPort ) { SetIPv4( unIP ); SetPort( usPort ); }
80 
81 	/// Attempt to parse address string.  Will never attempt
82 	/// DNS name resolution.  Returns false if we cannot parse an
83 	/// IPv4 address or IPv6 address.  If the port is not present,
84 	/// it is set to zero.
85 	bool    SetFromString( const char *psz );
86 
87 	/// Set to IPv4 broadcast address.  Does not change the port
SetIPV4Broadcast()88 	void	SetIPV4Broadcast() { SetIPv4( 0xffffffff ); }
89 
90 	/// Set to IPv6 broadcast (actually link scope all nodes) address on the specified
91 	/// IPv6 scope.  Does not change the port
92 	void	SetIPV6Broadcast( uint32 nScope = 0 ) { SetIPV6( k_ipv6Bytes_LinkLocalAllNodes, nScope ); }
93 
94 	/// Set to IPv4 loopback address (127.0.0.1).  Does not change the port
SetIPV4Loopback()95 	void	SetIPV4Loopback() { SetIPv4( 0x7f000001 ); }
96 
97 	/// Set to IPv6 loopback address (::1).  The scope is reset to zero.
98 	/// Does not change the port.
SetIPV6Loopback()99 	void	SetIPV6Loopback() { SetIPV6( k_ipv6Bytes_Loopback, 0 ); }
100 
101 	/// Set to IPV4 "any" address, i.e. INADDR_ANY = 0.0.0.0.
SetIPV4Any()102 	void	SetIPV4Any() { SetIPv4( 0 ); }
103 
104 	/// Set to IPV6 "any" address, i.e. IN6ADDR_ANY_INIT (all zeroes)
SetIPV6Any()105 	void	SetIPV6Any() { SetIPV6( k_ipv6Bytes_Any, 0 ); }
106 
107 	/// DNS resolution.  Blocking, so it may take a long time!  Inadvisable from the main thread!
108 	bool	BlockingResolveAndSetFromString( const char *psz, bool bUseIPv6 = false );
109 
110 	/// Returns true if two addresses are equal.
111 	bool	CompareAdr(const netadr_t &a, bool onlyBase = false) const;
112 
113 	/// Get the IPv4 IP, in host byte order.  Should only be called on IPv4 addresses.
114 	/// For historical reasons, this can be called on an NA_NULL address, and usually
115 	/// will return 0.
116 	uint	GetIPv4() const;
117 
118 	/// Fetch port (host byte order)
GetPort()119 	unsigned short GetPort() const { return port; }
120 
121 	/// Get IPv6 bytes.  This will work on any address type
122 	/// An NA_NULL address returns all zeros.
123 	/// For the IPv4 address aa.bb.cc.dd, we will return ::ffff:aabb:ccdd
124 	void GetIPV6( byte *result ) const;
125 
126 	/// Get pointer to IPV6 bytes.  This should only be called on IPv6
127 	/// address, will assert otherwise
128 	const byte *GetIPV6Bytes() const;
129 
130 	/// Set IPv6 address (as 16 bytes) and scope.
131 	/// This slams the address type to NA_IPV6, but
132 	/// does not alter the port.
133 	void SetIPV6( const byte *bytes, uint32 nScope = 0 );
134 
135 	/// Set IPv6 address (as 16 bytes), port, and scope.
136 	/// This also sets the address type to NA_IPV6.
137 	void SetIPV6AndPort( const byte *bytes, uint16 nPort, uint32 nScope = 0 ) { SetIPV6( bytes, nScope ); SetPort( nPort ); }
138 
139 	/// Get IPv6 scope ID
140 	uint32 GetIPV6Scope() const;
141 
142 	/// Set IPv6 scope.  This is only valid for IPv6 addresses.
143 	/// Will assert for other types
144 	void SetIPV6Scope( uint32 nScope );
145 
146 	/// Return true if we are an IPv4-mapped IPv6 address. (::ffff:1.2.3.4)
147 	bool IsMappedIPv4() const;
148 
149 	/// If we are an IPv4-mapped IPv6 address, convert to ordinary IPv4
150 	/// address and return true. Otherwise return false.  The port is not altered.
151 	bool BConvertMappedToIPv4();
152 
153 	/// If we are an ordinary IPv4 address, convert to a IPv4-mapped IPv6
154 	/// address and return true.  Otherwise return false.  The scope is cleared
155 	/// to zero, and the port is not altered.
156 	bool BConvertIPv4ToMapped();
157 
158 	/// Get string representation
159 	/// If onlyBase is true, then the port number is omitted.
160 	/// IPv4: xxx.xxx.xxx.xxx:ppppp
161 	/// IPv6: applies all of RFC5952 rules to get the canonical text representation.
162 	///       If !onlyBase, then the IP is surrounded by brackets to disambiguate colons
163 	///       in the address from the port separator: "[aabb::1234]:ppppp"
164 	void	ToString( char *pchBuffer, uint32 unBufferSize, bool onlyBase = false ) const;
165 
166 	/// ToString, but with automatic buffer size deduction
167 	template< size_t maxLenInChars >
168 	char*	ToString_safe( char (&pDest)[maxLenInChars], bool onlyBase = false ) const
169 	{
170 		ToString( &pDest[0], maxLenInChars, onlyBase );
171 		return	pDest;
172 	}
173 
174 	// Convert from any sockaddr-like struct
175 	bool SetFromSockadr(const void *addr, size_t addr_size);
SetFromSockadr(const T * s)176 	template <typename T> bool SetFromSockadr(const T *s) { return SetFromSockadr( s, sizeof(*s) ); }
177 
178 	// Convert to any sockaddr-like struct. Returns the size of the struct written.
179 	size_t ToSockadr(void *addr, size_t addr_size) const;
ToSockadr(T * s)180 	template <typename T> size_t ToSockadr(T *s) const { return ToSockadr( s, sizeof(*s) ); }
181 
182 	// Convert to sockaddr_in6.  If the address is IPv4 aa.bb.cc.dd, then
183 	// the mapped address ::ffff:aabb:ccdd is returned
184 	void ToSockadrIPV6(void *addr, size_t addr_size) const;
ToSockadrIPV6(T * s)185 	template <typename T> void ToSockadrIPV6(T *s) const { ToSockadrIPV6( s, sizeof(*s) ); }
186 
187 	bool	HasIP() const;
188 	bool	HasPort() const;
189 
190 	bool	IsLoopback() const;
191 	bool	IsReservedAdr() const;
192 	bool	IsBroadcast() const;
193 	bool	IsValid() const;	// ip & port != 0
194 	bool	SetFromSocket( int hSocket );
195 
196 	bool operator==(const netadr_t &netadr) const {return ( CompareAdr( netadr ) );}
197 	bool operator!=(const netadr_t &netadr) const {return !( CompareAdr( netadr ) );}
198 	bool operator<(const netadr_t &netadr) const;
199 	static unsigned int GetHashKey( const netadr_t &netadr );
200 	struct Hash
201 	{
operatorHash202 		inline unsigned int operator()( const netadr_t &x ) const
203 		{
204 			return netadr_t::GetHashKey( x );
205 		}
206 	};
207 private:
208 	unsigned short	type;				// netadrtype_t
209 	unsigned short	port;				// port stored in host order (little-endian)
210 	uint32			ipv6Scope;			// IPv6 scope
211 	union {
212 
213 		//
214 		// IPv4
215 		//
216 		uint			ip;				// IP stored in host order (little-endian)
217 		byte			ipByte[4];		// IP stored in host order (little-endian)
218 		struct
219 		{
220 			#ifdef VALVE_BIG_ENDIAN
221 				uint8 b1, b2, b3, b4;
222 			#else
223 				uint8 b4, b3, b2, b1;
224 			#endif
225 		} ipv4;
226 
227 		//
228 		// IPv6
229 		//
230 		byte			ipv6Byte[16];	// Same as inaddr_in6.  (0011:2233:4455:6677:8899:aabb:ccdd:eeff)
231 		uint64			ipv6Qword[2];	// In a few places we can use these to avoid memcmp. BIG ENDIAN!
232 	};
233 };
234 
235 COMPILE_TIME_ASSERT( sizeof(netadr_t) == 24 );
236 
237 #pragma pack(pop)
238 
239 
240 class CUtlNetAdrRender
241 {
242 public:
243 	CUtlNetAdrRender( const netadr_t &obj, bool bBaseOnly = false )
244 	{
245 		obj.ToString_safe( m_rgchString, bBaseOnly );
246 	}
247 
CUtlNetAdrRender(uint32 unIP)248 	CUtlNetAdrRender( uint32 unIP )
249 	{
250 		netadr_t addr( unIP, 0 );
251 		addr.ToString_safe( m_rgchString, true );
252 	}
253 
CUtlNetAdrRender(uint32 unIP,uint16 nPort)254 	CUtlNetAdrRender( uint32 unIP, uint16 nPort )
255 	{
256 		netadr_t addr( unIP, nPort );
257 		addr.ToString_safe( m_rgchString, false );
258 	}
259 
String()260 	const char * String()
261 	{
262 		return m_rgchString;
263 	}
264 
265 private:
266 
267 	char m_rgchString[k_ncchMaxNetAdrString];
268 };
269 
270 
SetIPv4(uint8 b1,uint8 b2,uint8 b3,uint8 b4)271 inline void netadr_t::SetIPv4(uint8 b1, uint8 b2, uint8 b3, uint8 b4)
272 {
273 	type = NA_IP;
274 	ip = ( b4 ) + ( b3 << 8 ) + ( b2 << 16 ) + ( b1 << 24 );
275 }
276 
SetIPv4(uint unIP)277 inline void netadr_t::SetIPv4(uint unIP)
278 {
279 	type = NA_IP;
280 	ip = unIP;
281 }
282 
SetType(netadrtype_t newtype)283 inline void netadr_t::SetType(netadrtype_t newtype)
284 {
285 	type = newtype;
286 }
287 
GetIPv4()288 inline uint netadr_t::GetIPv4() const
289 {
290 	if ( type != NA_IPV6 )
291 		return ip;
292 
293 	AssertMsg( false, "netadr_t::GetIP called on IPv6 address" );
294 	return 0;
295 }
296 
GetIPV6Bytes()297 inline const byte *netadr_t::GetIPV6Bytes() const
298 {
299 	Assert( type == NA_IPV6 );
300 	return ipv6Byte;
301 }
302 
SetIPV6(const byte * bytes,uint32 nScope)303 inline void netadr_t::SetIPV6( const byte *bytes, uint32 nScope )
304 {
305 	type = NA_IPV6;
306 	memcpy( ipv6Byte, bytes, 16 );
307 	ipv6Scope = nScope;
308 }
309 
GetIPV6Scope()310 inline uint32 netadr_t::GetIPV6Scope() const
311 {
312 	Assert( type == NA_IPV6 );
313 	return ipv6Scope;
314 }
315 
SetIPV6Scope(uint32 nScope)316 inline void netadr_t::SetIPV6Scope( uint32 nScope )
317 {
318 	Assert( type == NA_IPV6 );
319 	ipv6Scope = nScope;
320 }
321 
SetPort(unsigned short newport)322 inline void netadr_t::SetPort(unsigned short newport)
323 {
324 	port = newport;
325 }
326 
327 
328 #endif // NETADR_H
329