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