Stun Server  Compliant with the latest RFCs including 5389, 5769, and 5780
discover the local host's own external IP address
socketaddress.cpp
Go to the documentation of this file.
1 /*
2  Copyright 2011 John Selbie
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 
18 #include "commonincludes.hpp"
19 #include "socketaddress.h"
20 
21 
23 _address() // zero-init
24 {
25  _address.addr4.sin_family = AF_INET;
26 }
27 
28 CSocketAddress::CSocketAddress(const sockaddr& addr)
29 {
30  CommonConstructor(addr);
31 }
32 
33 CSocketAddress::CSocketAddress(const sockaddr_storage& addr)
34 {
35  CommonConstructor(*(sockaddr*)&addr);
36 }
37 
38 
39 void CSocketAddress::CommonConstructor(const sockaddr& addr)
40 {
41  ASSERT((addr.sa_family == AF_INET) || (addr.sa_family==AF_INET6));
42 
43  if (addr.sa_family == AF_INET6)
44  {
45  _address.addr6 = *(sockaddr_in6*)&addr;
46  }
47  else if (addr.sa_family == AF_INET)
48  {
49  _address.addr4 = *(sockaddr_in*)&addr;
50  }
51  else
52  {
53  _address.addr = addr;
54  }
55 }
56 
57 CSocketAddress::CSocketAddress(const sockaddr_in6& addr6)
58 {
59  ASSERT(addr6.sin6_family==AF_INET6);
60  _address.addr6 = addr6;
61 }
62 
63 CSocketAddress::CSocketAddress(const sockaddr_in& addr4)
64 {
65  ASSERT(addr4.sin_family == AF_INET);
66  _address.addr4 = addr4;
67 }
68 
69 CSocketAddress::CSocketAddress(uint32_t ipHostByteOrder, uint16_t port)
70 {
71  sockaddr_in addr = {};
72  addr.sin_family = AF_INET;
73  addr.sin_port = htons(port);
74  addr.sin_addr.s_addr = htonl(ipHostByteOrder);
75 
76  _address.addr4 = addr;
77 }
78 
79 uint16_t CSocketAddress::GetPort() const
80 {
81  return ntohs(GetPort_NBO());
82 }
83 
84 void CSocketAddress::SetPort(uint16_t port)
85 {
86  if (_address.addr.sa_family == AF_INET)
87  {
88  _address.addr4.sin_port = htons(port);
89  }
90  else
91  {
92  _address.addr6.sin6_port = htons(port);
93  }
94 }
95 
97 {
98  if (_address.addr.sa_family == AF_INET)
99  {
100  return _address.addr4.sin_port;
101  }
102  else
103  {
104  return _address.addr6.sin6_port;
105  }
106 }
107 
109 {
110  uint16_t length;
111 
112  if (_address.addr.sa_family == AF_INET)
113  {
114  length = sizeof(_address.addr4.sin_addr.s_addr);
115  }
116  else
117  {
118  length = sizeof(_address.addr6.sin6_addr.s6_addr);
119  }
120 
121  ASSERT((length == STUN_IPV4_LENGTH) || (length == STUN_IPV6_LENGTH));
122  return length;
123 }
124 
125 
126 size_t CSocketAddress::GetIPImpl(void* pAddr, size_t length, bool fNBO) const
127 {
128  HRESULT hr = S_OK;
129  size_t bytescopied = 0;
130 
131  ChkIfA(pAddr == NULL, E_INVALIDARG);
132  ChkIfA(length <= 0, E_INVALIDARG);
133  ChkIfA(length < GetIPLength(), E_INVALIDARG);
134 
135  ASSERT((_address.addr.sa_family == AF_INET)||(_address.addr.sa_family == AF_INET6));
136 
137  if (_address.addr.sa_family == AF_INET)
138  {
139  uint32_t ip = _address.addr4.sin_addr.s_addr;
140  if (fNBO==false)
141  {
142  ip = htonl(ip);
143  }
144  memcpy(pAddr, &ip, sizeof(ip));
145  bytescopied = sizeof(ip);
146  ASSERT(sizeof(ip) == STUN_IPV4_LENGTH);
147  }
148  else
149  {
150  // ipv6 addresses are the same in either byte ordering - just an array of 16 bytes
151  ASSERT(sizeof(_address.addr6.sin6_addr.s6_addr) == STUN_IPV6_LENGTH);
152 
153  memcpy(pAddr, &_address.addr6.sin6_addr.s6_addr, sizeof(_address.addr6.sin6_addr.s6_addr));
154  bytescopied = STUN_IPV6_LENGTH;
155  }
156 
157 Cleanup:
158  return bytescopied;
159 
160 }
161 
162 
163 size_t CSocketAddress::GetIP(void* pAddr, size_t length) const // returns the number of bytes copied, or Zero on error
164 {
165  return GetIPImpl(pAddr, length, false);
166 }
167 
168 
169 size_t CSocketAddress::GetIP_NBO(void* pAddr, size_t length) const // returns the number of bytes copied, or Zero on error
170 {
171  return GetIPImpl(pAddr, length, true);
172 }
173 
175 {
176  return _address.addr.sa_family;
177 }
178 
179 
181 {
182  const size_t iplen = (_address.addr.sa_family == AF_INET) ? STUN_IPV4_LENGTH : STUN_IPV6_LENGTH;
183  uint8_t* pPort;
184  uint8_t* pIP;
185 
186  if (_address.addr.sa_family == AF_INET)
187  {
188  COMPILE_TIME_ASSERT(sizeof(_address.addr4.sin_addr) == STUN_IPV4_LENGTH); // 4
189  COMPILE_TIME_ASSERT(sizeof(_address.addr4.sin_port) == 2);
190 
191  pPort = (uint8_t*)&(_address.addr4.sin_port);
192  pIP = (uint8_t*)&(_address.addr4.sin_addr);
193  }
194  else
195  {
196  COMPILE_TIME_ASSERT(sizeof(_address.addr6.sin6_addr) == STUN_IPV6_LENGTH); // 16
197  COMPILE_TIME_ASSERT(sizeof(_address.addr6.sin6_port) == 2);
198  pPort = (uint8_t*)&(_address.addr6.sin6_port);
199  pIP = (uint8_t*)&(_address.addr6.sin6_addr);
200  }
201 
202  pPort[0] = pPort[0] ^ transid.id[0];
203  pPort[1] = pPort[1] ^ transid.id[1];
204 
205  for (size_t i = 0; i < iplen; i++)
206  {
207  pIP[i] = pIP[i] ^ transid.id[i];
208  }
209 }
210 
211 
212 const sockaddr* CSocketAddress::GetSockAddr() const
213 {
214  return &_address.addr;
215 }
216 
218 {
219  if (_address.addr.sa_family == AF_INET)
220  {
221  return sizeof(_address.addr4);
222  }
223  else
224  {
225  return sizeof(_address.addr6);
226  }
227 }
228 
229 bool CSocketAddress::IsSameIP(const CSocketAddress& other) const
230 {
231  bool fRet = false;
232 
233 
234 
235  if (_address.addr.sa_family == other._address.addr.sa_family)
236  {
237  if (_address.addr.sa_family == AF_INET)
238  {
239  fRet = !memcmp(&_address.addr4.sin_addr, &other._address.addr4.sin_addr, sizeof(_address.addr4.sin_addr));
240  }
241  else if (_address.addr.sa_family == AF_INET6)
242  {
243  fRet = !memcmp(&_address.addr6.sin6_addr, &other._address.addr6.sin6_addr, sizeof(_address.addr6.sin6_addr));
244  }
245  else
246  {
247  ASSERT(false); // comparing an address that is neither IPV4 or IPV6?
248  fRet = !memcmp(&_address.addr.sa_data, &other._address.addr.sa_data, sizeof(_address.addr.sa_data));
249  }
250  }
251 
252  return fRet;
253 }
254 
256 {
257  return (IsSameIP(other) && (GetPort() == other.GetPort()) );
258 }
259 
260 
262 {
263  const static uint8_t ZERO_ARRAY[16] = {}; // zero init
264  bool fRet = false;
265 
266  if (_address.addr.sa_family == AF_INET)
267  {
268  fRet = !memcmp(&_address.addr4.sin_addr, ZERO_ARRAY, sizeof(_address.addr4.sin_addr));
269  }
270  else if (_address.addr.sa_family == AF_INET6)
271  {
272  fRet = !memcmp(&_address.addr6.sin6_addr, ZERO_ARRAY, sizeof(_address.addr6.sin6_addr));
273  }
274  else
275  {
276  ASSERT(false); // comparing an address that is neither IPV4 or IPV6?
277  fRet = !memcmp(&_address.addr.sa_data, ZERO_ARRAY, sizeof(_address.addr.sa_data));
278  }
279 
280  return fRet;
281 }
282 
283 
284 void CSocketAddress::ToString(std::string* pStr) const
285 {
286  char sz[INET6_ADDRSTRLEN + 6];
287  ToStringBuffer(sz, ARRAYSIZE(sz));
288  *pStr = sz;
289 }
290 HRESULT CSocketAddress::ToStringBuffer(char* pszAddrBytes, size_t length) const
291 {
292  HRESULT hr = S_OK;
293  int family = GetFamily();
294  const void *pAddrBytes = NULL;
295  const char* pszResult = NULL;
296  const size_t portLength = 6; // colon plus 5 digit string e.g. ":55555"
297  char szPort[portLength+1];
298  char delimiter = (family == AF_INET) ? ':' : '.';
299 
300 
301  ChkIfA(pszAddrBytes == NULL, E_INVALIDARG);
302  ChkIf(length <= 0, E_INVALIDARG);
303  pszAddrBytes[0] = 0;
304 
305  if (family == AF_INET)
306  {
307  pAddrBytes = &(_address.addr4.sin_addr);
308  ChkIf(length < (INET_ADDRSTRLEN+portLength), E_INVALIDARG);
309  }
310  else if (family == AF_INET6)
311  {
312  pAddrBytes = &(_address.addr6.sin6_addr);
313  ChkIf(length < (INET6_ADDRSTRLEN+portLength), E_INVALIDARG);
314  }
315  else
316  {
317  ChkA(E_FAIL);
318  }
319 
320  pszResult = ::inet_ntop(family, pAddrBytes, pszAddrBytes, length);
321 
322  ChkIf(pszResult == NULL, ERRNOHR);
323 
324  sprintf(szPort, "%c%d", delimiter, GetPort());
325 #if DEBUG
326  ChkIfA(strlen(szPort) > portLength, E_FAIL);
327 #endif
328 
329  strcat(pszAddrBytes, szPort);
330 
331 Cleanup:
332  return hr;
333 }
334 
335 
336 
338 {
339 
340  if ( ((family != AF_INET) && (family != AF_INET6)) ||
341  (pAddr == NULL))
342  {
343  ASSERT(false);
344  return E_FAIL;
345  }
346 
347  if (family == AF_INET)
348  {
349  uint32_t ip = 0x7f000001; // 127.0.0.1 in host byte order
350  *pAddr = CSocketAddress(ip, 0);
351  }
352  else
353  {
354  sockaddr_in6 addr6 = {};
355  COMPILE_TIME_ASSERT(sizeof(addr6.sin6_addr) == 16);
356 
357  // ::1
358  uint8_t ip6[16] = {};
359  ip6[15] = 1;
360 
361  addr6.sin6_family = AF_INET6;
362  memcpy(&addr6.sin6_addr, ip6, 16);
363  *pAddr = CSocketAddress(addr6);
364  }
365 
366  return S_OK;
367 }
368 
#define S_OK
Definition: hresult.h:46
#define ASSERT(expr)
size_t GetIPImpl(void *pAddr, size_t length, bool fNetworkByteOrder) const
socklen_t GetSockAddrLength() const
uint16_t GetIPLength() const
const uint16_t STUN_IPV6_LENGTH
Definition: stuntypes.h:81
bool IsSameIP_and_Port(const CSocketAddress &other) const
void ApplyStunXorMap(const StunTransactionId &id)
static HRESULT GetLocalHost(uint16_t family, CSocketAddress *pAddr)
uint16_t GetPort() const
#define ARRAYSIZE(arr)
#define ChkIf(expr, hrerror)
Definition: chkmacros.h:63
size_t GetIP_NBO(void *pAddr, size_t length) const
const uint16_t STUN_IPV4_LENGTH
Definition: stuntypes.h:80
void SetPort(uint16_t)
sockaddr_in6 addr6
Definition: socketaddress.h:28
bool IsSameIP(const CSocketAddress &other) const
simple_sockaddr _address
Definition: socketaddress.h:34
int32_t HRESULT
Definition: hresult.h:22
#define COMPILE_TIME_ASSERT(x)
const sockaddr * GetSockAddr() const
size_t GetIP(void *pAddr, size_t length) const
void ToString(std::string *pStr) const
sockaddr_in addr4
Definition: socketaddress.h:27
HRESULT ToStringBuffer(char *pszAddrBytes, size_t length) const
#define E_INVALIDARG
Definition: hresult.h:51
uint8_t id[STUN_TRANSACTION_ID_LENGTH]
Definition: stuntypes.h:154
uint16_t GetPort_NBO() const
#define E_FAIL
Definition: hresult.h:56
#define ChkA(expr)
Definition: chkmacros.h:73
uint16_t GetFamily() const
bool IsIPAddressZero() const
#define ChkIfA(expr, hrerror)
Definition: chkmacros.h:84
#define ERRNOHR
Definition: hresult.h:42
void CommonConstructor(const sockaddr &addr)