Stun Server  Compliant with the latest RFCs including 5389, 5769, and 5780
discover the local host's own external IP address
adapters.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 
20 // TODO - FIX THIS SUCH THAT CSocketAddress is in it's own "base" library independent of networkutils and stuncore
21 #include "socketaddress.h"
22 
23 
24 void GetDefaultAdapters(int family, ifaddrs* pList, ifaddrs** ppAddrPrimary, ifaddrs** ppAddrAlternate)
25 {
26  ifaddrs* pAdapter = NULL;
27 
28  *ppAddrPrimary = NULL;
29  *ppAddrAlternate = NULL;
30 
31  pAdapter = pList;
32  while (pAdapter)
33  {
34  if ( (pAdapter->ifa_addr != NULL) && (pAdapter->ifa_addr->sa_family == family) && (pAdapter->ifa_flags & IFF_UP) && !(pAdapter->ifa_flags & IFF_LOOPBACK))
35  {
36  if (*ppAddrPrimary == NULL)
37  {
38  *ppAddrPrimary = pAdapter;
39  }
40  else
41  {
42  *ppAddrAlternate = pAdapter;
43  break;
44  }
45  }
46  pAdapter = pAdapter->ifa_next;
47  }
48 }
49 
54 bool HasAtLeastTwoAdapters(int family)
55 {
56  HRESULT hr = S_OK;
57 
58  ifaddrs* pList = NULL;
59  ifaddrs* pAdapter1 = NULL;
60  ifaddrs* pAdapter2 = NULL;
61  bool fRet = false;
62 
63  ChkIf(getifaddrs(&pList) < 0, ERRNOHR);
64 
65  GetDefaultAdapters(family, pList, &pAdapter1, &pAdapter2);
66 
67  fRet = (pAdapter1 && pAdapter2);
68 
69 
70 Cleanup:
71  freeifaddrs(pList);
72  return fRet;
73 }
74 
75 
83 HRESULT GetBestAddressForSocketBind(bool fPrimary, int family, uint16_t port, CSocketAddress* pSocketAddr)
84 {
85  HRESULT hr = S_OK;
86  ifaddrs* pList = NULL;
87  ifaddrs* pAdapter = NULL;
88  ifaddrs* pAdapter1 = NULL;
89  ifaddrs* pAdapter2 = NULL;
90 
91  ChkIfA(pSocketAddr == NULL, E_INVALIDARG);
92 
93  ChkIf(getifaddrs(&pList) < 0, ERRNOHR);
94 
95  GetDefaultAdapters(family, pList, &pAdapter1, &pAdapter2);
96 
97  pAdapter = fPrimary ? pAdapter1 : pAdapter2;
98 
99  ChkIf(pAdapter==NULL, E_FAIL);
100  ChkIfA(pAdapter->ifa_addr==NULL, E_UNEXPECTED);
101 
102  *pSocketAddr = CSocketAddress(*pAdapter->ifa_addr);
103  pSocketAddr->SetPort(port);
104 
105 Cleanup:
106  freeifaddrs(pList);
107  return hr;
108 }
109 
110 
111 HRESULT GetSocketAddressForAdapter(int family, const char* pszAdapterName, uint16_t port, CSocketAddress* pSocketAddr)
112 {
113  HRESULT hr = S_OK;
114  ifaddrs* pList = NULL;
115  ifaddrs* pAdapter = NULL;
116  ifaddrs* pAdapterFound = NULL;
117 
118 
119  ChkIfA(pszAdapterName == NULL, E_INVALIDARG);
120  ChkIfA(pszAdapterName[0] == '\0', E_INVALIDARG);
121  ChkIfA(pSocketAddr == NULL, E_INVALIDARG);
122 
123 
124 
125  // what if the socket address is available, but not "up". Well, just let this call succeed. If the server errors out, it will get cleaned up then
126  ChkIf(getifaddrs(&pList) < 0, ERRNOHR);
127  pAdapter = pList;
128  while (pAdapter)
129  {
130  if ((pAdapter->ifa_addr != NULL) && (pAdapter->ifa_name != NULL) && (family == pAdapter->ifa_addr->sa_family))
131  {
132  if (strcmp(pAdapter->ifa_name, pszAdapterName) == 0)
133  {
134  pAdapterFound = pAdapter;
135  break;
136  }
137  }
138  pAdapter = pAdapter->ifa_next;
139  }
140 
141 
142  // If pszAdapterName is an IP address, convert it into a sockaddr and compare the address field with that of the adapter
143  // Note: an alternative approach would be to convert pAdapter->ifa_addr to a string and then do a string compare.
144  // But then it would be difficult to match "::1" with "0:0:0:0:0:0:0:1" and other formats of IPV6 strings
145  if ((pAdapterFound == NULL) && ((family == AF_INET) || (family == AF_INET6)) )
146  {
147  uint8_t addrbytes[sizeof(in6_addr)] = {};
148  int comparesize = (family == AF_INET) ? sizeof(in_addr) : sizeof(in6_addr);
149  void* pCmp = NULL;
150 
151 
152  if (inet_pton(family, pszAdapterName, addrbytes) == 1)
153  {
154  pAdapter = pList;
155  while (pAdapter)
156  {
157  if ((pAdapter->ifa_addr != NULL) && (family == pAdapter->ifa_addr->sa_family))
158  {
159  // offsetof(sockaddr_in, sin_addr) != offsetof(sockaddr_in6, sin6_addr)
160  // so you really can't do too many casting tricks like you can with sockaddr and sockaddr_in
161 
162  if (family == AF_INET)
163  {
164  sockaddr_in *pAddr4 = (sockaddr_in*)(pAdapter->ifa_addr);
165  pCmp = &(pAddr4->sin_addr);
166  }
167  else
168  {
169  sockaddr_in6 *pAddr6 = (sockaddr_in6*)(pAdapter->ifa_addr);
170  pCmp = &(pAddr6->sin6_addr);
171  }
172 
173  if (memcmp(pCmp, addrbytes, comparesize) == 0)
174  {
175  // match on ip address string found
176  pAdapterFound = pAdapter;
177  break;
178  }
179  }
180  pAdapter = pAdapter->ifa_next;
181  }
182  }
183  }
184 
185  ChkIf(pAdapterFound == NULL, E_FAIL);
186 
187  {
188  *pSocketAddr = CSocketAddress(*(pAdapterFound->ifa_addr));
189  pSocketAddr->SetPort(port);
190  }
191 
192 Cleanup:
193 
194  freeifaddrs(pList);
195  return hr;
196 
197 }
198 
199 
#define S_OK
Definition: hresult.h:46
void GetDefaultAdapters(int family, ifaddrs *pList, ifaddrs **ppAddrPrimary, ifaddrs **ppAddrAlternate)
Definition: adapters.cpp:24
#define ChkIf(expr, hrerror)
Definition: chkmacros.h:63
HRESULT GetSocketAddressForAdapter(int family, const char *pszAdapterName, uint16_t port, CSocketAddress *pSocketAddr)
Definition: adapters.cpp:111
#define E_UNEXPECTED
Definition: hresult.h:48
HRESULT GetBestAddressForSocketBind(bool fPrimary, int family, uint16_t port, CSocketAddress *pSocketAddr)
Definition: adapters.cpp:83
void SetPort(uint16_t)
int32_t HRESULT
Definition: hresult.h:22
#define E_INVALIDARG
Definition: hresult.h:51
#define E_FAIL
Definition: hresult.h:56
bool HasAtLeastTwoAdapters(int family)
Definition: adapters.cpp:54
#define ChkIfA(expr, hrerror)
Definition: chkmacros.h:84
#define ERRNOHR
Definition: hresult.h:42