RDK Documentation (Open Sourced RDK Components)
StunClient.cpp
1 #include "StunClient.h"
2 #include "NetworkMgrMain.h"
3 #include "netsrvmgrUtiles.h"
4 #include "netsrvmgrIarm.h"
5 #include <assert.h>
6 #include <arpa/inet.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <ifaddrs.h>
10 #include <netdb.h>
11 #include <net/if.h>
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <algorithm>
17 #include <exception>
18 #include <limits>
19 #include <memory>
20 #include <random>
21 #include <set>
22 #include <sstream>
23 #include <thread>
24 #include <iostream>
25 
26 #define STUN_DEFAULT_WAIT_INTERVAL 2000 //miliseconds
27 #define STUN_DEFAULT_MAX_ATTEMPTS 30
28 
29 //#define _STUN_DEBUG 1
30 //#define _STUN_USE_MSGHDR
31 
32 namespace stun {
33 namespace details {
34  static int constexpr binding_requests_max = 9;
35  static std::chrono::milliseconds binding_requests_wait_time_max(1600);
36 
37  static char const * family_to_string(int family) {
38  if (family == AF_INET)
39  return "ipv4";
40  if (family == AF_INET6)
41  return "ipv6";
42  return "unknown";
43  }
44 
46  public:
47  file_descriptor(int n) : m_fd(n) { }
48  ~file_descriptor() {
49  if (m_fd > 0)
50  close(m_fd);
51  }
52  operator int() const { return m_fd; }
53  private:
54  int m_fd;
55  };
56 
57  #ifdef _STUN_DEBUG
58  void dump_buffer(char const * prefix, buffer const & buff)
59  {
60  if (prefix)
61  printf("%s", prefix);
62  for (uint8_t b : buff)
63  printf("0x%02x ", b);
64  printf("\n");
65  }
66  #endif
67 
68  #ifdef _STUN_DEBUG
69  #define STUN_TRACE(format, ...) printf("STUN:" format __VA_OPT__(,) __VA_ARGS__)
70  #else
71  #define STUN_TRACE(format, ...)
72  #endif
73 
74 
75  void throw_error(char const * format, ...)
76  {
77  char buff[256] = {};
78 
79  va_list ap;
80  va_start(ap, format);
81  vsnprintf(buff, sizeof(buff) - 1, format, ap);
82  va_end(ap);
83 
84  buff[255] = '\0';
85 #ifdef __cpp_exceptions
86  throw std::runtime_error(buff);
87 #else
88  LOG_ERR("%s", buff);
89 #endif
90  }
91 
92  template<typename iterator>
93  inline void random_fill(iterator begin, iterator end) {
94  std::random_device rdev;
95  std::default_random_engine random_engine(rdev());
96  std::uniform_int_distribution<uint8_t> uniform_dist(0, std::numeric_limits<uint8_t>::max());
97  while (begin != end)
98  *begin++ = uniform_dist(random_engine);
99  }
100 
101  sockaddr_storage get_interface_address(std::string const & iface, int family)
102  {
103  bool found_iface_info = false;
104  sockaddr_storage iface_info = {};
105 
106  struct ifaddrs * address_list = nullptr;
107  if (getifaddrs(&address_list) == -1) {
108  details::throw_error("getifaddrs failed. %s", strerror(errno));
109  return iface_info;
110  }
111 
112  for (auto * addr = address_list; addr != nullptr; addr = addr->ifa_next) {
113  if (iface != addr->ifa_name)
114  continue;
115  if (family != addr->ifa_addr->sa_family)
116  continue;
117  iface_info = * reinterpret_cast<sockaddr_storage *>(addr->ifa_addr);
118  iface_info.ss_family = addr->ifa_addr->sa_family;
119  found_iface_info = true;
120  break;
121  }
122 
123  if (address_list)
124  freeifaddrs(address_list);
125 
126  if (!found_iface_info) {
127  details::throw_error("failed to find ip for interface:%s", iface.c_str());
128  return iface_info;
129  }
130  STUN_TRACE("local_addr:%s\n", sockaddr_to_string(iface_info).c_str());
131 
132  return iface_info;
133  }
134 
135  uint16_t sockaddr_get_port(sockaddr_storage const & addr)
136  {
137  uint16_t port = 0;
138  if (addr.ss_family== AF_INET) {
139  sockaddr_in const * v4 = reinterpret_cast< sockaddr_in const *>(&addr);
140  port = htons(v4->sin_port);
141  }
142  else if (addr.ss_family == AF_INET6) {
143  sockaddr_in6 const * v6 = reinterpret_cast< sockaddr_in6 const *>(&addr);
144  port = htons(v6->sin6_port);
145  }
146  else
147  throw_error("can't convert address with family:%d to a string.", addr.ss_family);
148 
149  return port;
150  }
151 
152  std::string sockaddr_to_string2(sockaddr const * addr, int family)
153  {
154  char buff[INET6_ADDRSTRLEN] = {};
155 
156  char const * p = nullptr;
157 
158  if (family == AF_INET) {
159  sockaddr_in const * v4 = reinterpret_cast< sockaddr_in const *>(addr);
160  p = inet_ntop(AF_INET, &v4->sin_addr, buff, INET6_ADDRSTRLEN);
161  }
162  else if (family == AF_INET6) {
163  sockaddr_in6 const * v6 = reinterpret_cast< sockaddr_in6 const *>(addr);
164  p = inet_ntop(AF_INET6, &v6->sin6_addr, buff, INET6_ADDRSTRLEN);
165  }
166  else
167  throw_error("can't convert address with family:%d to a string.", family);
168 
169  if (!p)
170  throw_error("failed to convert address to string");
171 
172  buff[INET6_ADDRSTRLEN - 1] = '\0';
173  return std::string(buff);
174  }
175 
176  std::vector<sockaddr_storage> resolve_hostname(std::string const & host, uint16_t port, stun::protocol proto)
177  {
178  std::vector<sockaddr_storage> addrs;
179  std::set<std::string> already_seen;
180 
181  struct addrinfo * stun_addrs = nullptr;
182  int ret = getaddrinfo(host.c_str(), nullptr, nullptr, &stun_addrs);
183  if (ret != 0) {
184  std::stringstream error_message;
185  error_message << "getaddrinfo failed. ";
186  if (ret == EAI_SYSTEM)
187  error_message << strerror(errno);
188  else
189  error_message << gai_strerror(ret);
190  throw_error(error_message.str().c_str());
191  }
192 
193  int protocol_family;
194  if (proto == stun::protocol::af_inet)
195  protocol_family = AF_INET;
196  else if (proto == stun::protocol::af_inet6)
197  protocol_family = AF_INET6;
198  else
199  throw_error("invalid protocol family");
200 
201  for (struct addrinfo * addr = stun_addrs; addr; addr = addr->ai_next) {
202  if (addr->ai_family != AF_INET && addr->ai_family != AF_INET6)
203  continue;
204  if (addr->ai_family != protocol_family)
205  continue;
206 
207  std::string const s = sockaddr_to_string2(addr->ai_addr, addr->ai_family);
208 
209  if (already_seen.find(s) == std::end(already_seen)) {
210  struct sockaddr_storage temp = {};
211  memcpy(&temp, addr->ai_addr, addr->ai_addrlen);
212 
213  if (addr->ai_family == AF_INET) {
214  sockaddr_in * v4 = reinterpret_cast< sockaddr_in *>(&temp);
215  v4->sin_port = ntohs(port);
216  }
217  else if (addr->ai_family == AF_INET6) {
218  sockaddr_in6 * v6 = reinterpret_cast< sockaddr_in6 *>(&temp);
219  v6->sin6_port = ntohs(port);
220  }
221 
222  addrs.push_back(temp);
223  already_seen.insert(s);
224  }
225  }
226 
227  if (stun_addrs)
228  freeaddrinfo(stun_addrs);
229 
230  return addrs;
231  }
232 
233  socklen_t socket_length(sockaddr_storage const & addr)
234  {
235  if (addr.ss_family == AF_INET)
236  return sizeof(sockaddr_in);
237  if (addr.ss_family == AF_INET6)
238  return sizeof(sockaddr_in6);
239  return 0;
240  }
241 
242 } // end namespace details
243 
244 attribute const * message::find_attribute(uint16_t attr_type) const
245 {
246  std::vector<attribute>::const_iterator itr = std::find_if (
247  std::begin(m_attrs), std::end(m_attrs), [attr_type](attribute const & attr) {
248  return attr_type == attr.type;
249  });
250  if (itr == m_attrs.end())
251  return nullptr;
252  attribute const & temp = *itr;
253  return &temp;
254 }
255 
256 
257 buffer message::encode() const
258 {
259  buffer bytes;
260  encoder::encode_u16(bytes, m_header.message_type);
261  encoder::encode_u16(bytes, m_header.message_length);
262  for (uint8_t b : m_header.transaction_id)
263  bytes.push_back(static_cast<uint8_t>(b));
264  for (attribute const & v : m_attrs) {
265  encoder::encode_u16(bytes, v.type);
266  encoder::encode_u16(bytes, v.length);
267  bytes.insert(std::end(bytes), std::begin(v.value), std::end(v.value));
268  }
269  return bytes;
270 }
271 
272 message * message_factory::create_binding_request()
273 {
274  message * change_request = new message();
275  change_request->m_header.message_type = 1;
276  change_request->m_header.message_length = 8;
277  details::random_fill(std::begin(change_request->m_header.transaction_id),
278  std::end(change_request->m_header.transaction_id));
279 
280  // CHANGE-REQUEST
281  change_request->m_attrs.push_back({3, 4, {0, 0, 0, 0}});
282 
283  return change_request;
284 }
285 
286 client::client()
287  : m_server("", 0)
288  , m_interface("")
289  , m_protocol(protocol::af_inet)
290  , m_bind_timeout(30)
291  , m_cache_timeout(30)
292  , m_last_cache_time()
293  , m_last_result()
294  , m_verbose(false)
295  , m_fd(-1)
296 {
297 }
298 
299 client::~client()
300 {
301  if (m_fd != -1)
302  close(m_fd);
303 }
304 
305 bool client::bind(
306  std::string const & hostname,
307  uint16_t port,
308  std::string const & interface,
309  protocol proto,
310  uint16_t bind_timeout,
311  uint16_t cache_timeout,
312  bind_result& result)
313 {
314  /*if params change then we force a bind request now instead of using any cached value*/
315  bool dirty = false;
316  bool ret_ok = false;
317 
318  if(m_server.hostname != hostname)
319  {
320  m_server.hostname = hostname;
321  dirty = true;
322  }
323 
324  if(m_server.port != port)
325  {
326  m_server.port = port;
327  dirty = true;
328  }
329 
330  if(m_interface != interface)
331  {
332  m_interface = interface;
333  dirty = true;
334  }
335 
336  if(m_protocol != proto)
337  {
338  m_protocol = proto;
339  dirty = true;
340  }
341 
342  if(m_bind_timeout != bind_timeout)
343  {
344  m_bind_timeout = bind_timeout;
345  dirty = true;
346  }
347 
348  if(m_cache_timeout != cache_timeout)
349  {
350  m_cache_timeout = cache_timeout;
351  dirty = true;
352  }
353 
354  LOG_WARN( "stun::client::bind enter: server=%s port=%u iface=%s ipv6=%u timeout=%u cache_timeout=%u dirty=%u",
355  hostname.c_str(), port, interface.c_str(), proto == stun::protocol::af_inet6, bind_timeout, cache_timeout, dirty);
356  verbose("client::bind enter: server=%s port=%u iface=%s ipv6=%u timeout=%u cache_timeout=%u dirty=%u\n",
357  hostname.c_str(), port, interface.c_str(), proto == stun::protocol::af_inet6, bind_timeout, cache_timeout, dirty);
358 
359  if(m_cache_timeout > 0 /*asking if caching is enabled*/
360  && !dirty /*if dirty then the caller has changed our settings and wants a new bind no matter what*/
361  && m_last_result.is_valid()) /*we actually have a valid cached response*/
362  {
363  auto time_in_cache = std::chrono::duration_cast<std::chrono::seconds>(
364  std::chrono::steady_clock::now() - m_last_cache_time);
365 
366  LOG_DBG("stun::client::bind cache time=%lld", time_in_cache.count());
367  verbose("client::bind cache time=%lld\n", time_in_cache.count());
368 
369  if(time_in_cache.count() < m_cache_timeout)
370  {
371  result = m_last_result;
372 
373  LOG_DBG("stun::client::bind returning cached result: %s", result.public_ip.c_str());
374  verbose("client::bind returning cached result: %s\n", result.public_ip.c_str());
375  return true;
376  }
377  else
378  {
379  LOG_DBG("stun::client::bind cached result expired");
380  verbose("client::client::bind cached result expired\n");
381  }
382  }
383 
384  #ifdef __cpp_exceptions
385  try
386  #endif
387  {
388  int interval_wait_time = STUN_DEFAULT_WAIT_INTERVAL;
389  int num_attempts = STUN_DEFAULT_MAX_ATTEMPTS;
390  int total_time = 0;
391  int sleep_time = 1;
392 
393  std::chrono::milliseconds wait_time(interval_wait_time);
394  for (int i = 0; i < num_attempts && total_time < m_bind_timeout; ++i)
395  {
396  LOG_DBG("stun::client::bind sending bind request");
397  verbose("client::bind sending bind request\n");
398 
399  std::unique_ptr<stun::message> binding_response = send_binding_request(wait_time);
400 
401  total_time += interval_wait_time;/*FXIME should do a clock delta and not use wait_time which is the max*/
402  /*do a multiple of 2 sleep -- FIXIME should use cond variable so user to cancel this*/
403  if (i > 0)
404  {
405  if (total_time + sleep_time > m_bind_timeout)
406  sleep_time = m_bind_timeout - total_time;
407  if (sleep_time < 0)
408  break;
409  sleep(sleep_time);
410  total_time += sleep_time;
411  if (sleep_time < 32)/*put some max limit on how long we wait*/
412  sleep_time *= 2;
413  }
414  if (binding_response)
415  {
416  stun::attribute const * mapped_address = binding_response->find_attribute(stun::attribute_type::mapped_address);
417  if (mapped_address)
418  {
419  sockaddr_storage addr = stun::attributes::mapped_address(*mapped_address).addr();
420 
421  result.public_ip = m_last_result.public_ip = stun::sockaddr_to_string(addr);
422 
423  m_last_cache_time = std::chrono::steady_clock::now();
424 
425  LOG_DBG("stun::client::bind success: public_ip=%s", result.public_ip.c_str());
426  verbose("client::bind success: public_ip=%s\n", result.public_ip.c_str());
427 
428  ret_ok = true;
429  }
430  else
431  {
432  LOG_ERR("stun::client::bind failed: ip missing from binding response");
433  verbose("client::bind failed: ip missing from binding response\n");
434  }
435  }
436  else
437  {
438  LOG_ERR("stun::client::bind failed: no response received from server");
439  verbose("client::bind failed: no response received from server\n");
440  }
441  }
442  }
443 #ifdef __cpp_exceptions
444  catch (std::exception const & err)
445  {
446  LOG_ERR("stun fail: %s", err.what());
447  verbose("client::bind failed: %s\n", err.what());
448  }
449 #endif
450 
451  if (m_fd != -1)
452  {
453  close(m_fd);
454  m_fd = -1;
455  }
456 
457  if(!ret_ok)
458  result.invalidate();
459 
460  return ret_ok;
461 }
462 
463 void client::create_udp_socket(int inet_family)
464 {
465  if (inet_family != AF_INET && inet_family != AF_INET6)
466  details::throw_error("invalid inet family:%d", inet_family);
467 
468  verbose("creating udp/%s socket\n", details::family_to_string(inet_family));
469 
470  int soc = socket(inet_family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
471  if (soc < 0)
472  details::throw_error("error creating socket. %s", strerror(errno));
473 
474  #ifdef _SUN_USE_MSGHDR
475  int optval = 1;
476  setsockopt(soc, IPPROTO_IP, IP_PKTINFO, &optval, sizeof(int));
477  #endif
478 
479  if (!m_interface.empty()) {
480  int ret;
482  if (!netSrvMgrUtiles::getInterfaceConfig(m_interface.c_str(), inet_family, param.ipaddress, param.netmask)) {
483  LOG_ERR("stb %d ipaddress not found.", inet_family);
484  return;
485  }
486 
487  verbose("interface:%s, ipaddres:%s, netmask:%s\n", m_interface.c_str(), param.ipaddress, param.netmask);
488  struct sockaddr_in serv_addr;
489  struct sockaddr_in6 serv_ipv6;
490  struct in_addr addrptr;
491  if(inet_family == AF_INET) {
492  inet_aton(param.ipaddress, &addrptr);
493  serv_addr.sin_family = inet_family;
494  serv_addr.sin_port = htons(m_server.port);
495  serv_addr.sin_addr = addrptr;
496  ret = ::bind(soc, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
497  } else if(inet_family == AF_INET6) {
498  inet_pton(AF_INET6, param.ipaddress, &serv_ipv6.sin6_addr);
499  serv_ipv6.sin6_family = inet_family;
500  serv_ipv6.sin6_port = htons(m_server.port);
501  ret = ::bind(soc, (struct sockaddr *)&serv_ipv6, sizeof(serv_ipv6));
502  }
503  if (ret < 0) {
504  int err = errno;
505  close(soc);
506  details::throw_error("failed to bind socket to local address '%s'. %s",
507  param.ipaddress, strerror(err));
508  }
509  else {
510  if (m_verbose) {
511  sockaddr_storage local_endpoint;
512  socklen_t socklen = sizeof(sockaddr_storage);
513  int ret = getsockname(soc, reinterpret_cast<sockaddr *>(&local_endpoint), &socklen);
514  if (ret == 0)
515  verbose("local endpoint %s/%d\n", sockaddr_to_string(local_endpoint).c_str(),
516  details::sockaddr_get_port(local_endpoint));
517  }
518  }
519  }
520  else
521  verbose("no local interface supplied to bind to\n");
522 
523  if (m_fd != -1)
524  close(m_fd);
525  m_fd = soc;
526 }
527 
528 message * client::send_message(sockaddr_storage const & remote_addr, message const & req,
529  std::chrono::milliseconds wait_time, int * local_iface_index)
530 {
531  if (m_fd < 0)
532  return nullptr;
533 
534  buffer bytes = req.encode();
535 
536  STUN_TRACE("remote_addr:%s\n", sockaddr_to_string(remote_addr).c_str());
537 
538  #ifdef _STUN_DEBUG
539  details::dump_buffer("STUN >>> ", bytes);
540  #endif
541 
542  verbose("sending messsage\n");
543 
544  ssize_t n = sendto(m_fd, &bytes[0], bytes.size(), 0, (sockaddr *) &remote_addr, details::socket_length(remote_addr));
545  if (n < 0)
546  details::throw_error("failed to send packet. %s", strerror(errno));
547 
548  bytes.resize(0);
549  bytes.reserve(256);
550  bytes.resize(256);
551 
552  sockaddr_storage from_addr = {};
553 
554  fd_set rfds;
555  FD_ZERO(&rfds);
556  FD_SET(m_fd, &rfds);
557 
558  timeval timeout;
559  timeout.tv_usec = 1000 * wait_time.count();
560  timeout.tv_sec = 0;
561 
562  constexpr decltype(timeout.tv_sec) kMicrosecondsPerSecond = 1000000;
563  if (timeout.tv_usec > kMicrosecondsPerSecond) {
564  timeout.tv_sec = (timeout.tv_usec / kMicrosecondsPerSecond);
565  timeout.tv_usec -= (timeout.tv_sec * kMicrosecondsPerSecond);
566  }
567  verbose("waiting for response, timeout set to %lus - %luus\n", timeout.tv_sec, timeout.tv_usec);
568  int ret = select(m_fd + 1, &rfds, nullptr, nullptr, &timeout);
569  if (ret == 0) {
570  STUN_TRACE("select timeout out\n");
571  return nullptr;
572  }
573 
574  //
575  // XXX: For discovering the network type, the first test is to run a binding request and
576  // compare the response to the local address/port combo. I was attempting to find the
577  // local address/port without an explicit bind() on the local socket fd. You can usethe
578  // recvmsg() to get the interface index where the UDP packets come in, but you can't get
579  // the port. For now, in order for the discovery to work, you have to choose a local
580  // interface name, and call bind() on the addr.
581  //
582  // At some point, I'll come back to this and check whether you can find the port without
583  // an explicit bind, possibly using sendmsg() or another option.
584  // @see [in this file] client::create_udp_socket(), there's a call to setsockopt() which
585  // enables the retrieval of the IP_PKTINFO
586  //
587  #ifdef _STUN_USE_MSGHDR
588  do {
589  //buffer control( CMSG_SPACE(sizeof(struct in_addr)) + CMSG_SPACE(sizeof(struct in_pktinfo)) +
590  // sizeof(struct cmsghdr) );
591  uint8_t control_data[256];
592 
593  struct msghdr msg = {};
594  struct iovec iov = {};
595 
596  iov.iov_base = &bytes[0];
597  iov.iov_len = bytes.size();
598 
599  msg.msg_flags = 0;
600  msg.msg_iov = &iov;
601  msg.msg_iovlen = 1;
602  msg.msg_control = control_data;
603  msg.msg_controllen = sizeof(control_data);
604  msg.msg_name = &from_addr;
605  msg.msg_namelen = sizeof(from_addr);
606 
607  n = recvmsg(m_fd, &msg, 0);
608  if ((n > 0) && local_iface_index) {
609  for (cmsghdr * cptr = CMSG_FIRSTHDR(&msg); cptr; cptr = CMSG_NXTHDR(&msg, cptr)) {
610  if (cptr->cmsg_level == IPPROTO_IP) {
611  if (cptr->cmsg_type == IP_PKTINFO)
612  *local_iface_index = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cptr))->ipi_ifindex;
613  else if (cptr->cmsg_type == IPV6_PKTINFO)
614  *local_iface_index = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cptr))->ipi6_ifindex;
615  }
616  }
617  }
618  } while (n < 0 && errno == EINTR);
619  #else
620  do {
621  socklen_t len = sizeof(sockaddr_storage);
622  n = recvfrom(m_fd, &bytes[0], bytes.size(), MSG_WAITALL, (sockaddr *) &from_addr, &len);
623  } while (n == -2 && errno == EINTR);
624  #endif
625 
626  if (n < 0)
627  details::throw_error("error receiving on socket. %s", strerror(errno));
628  else
629  bytes.resize(n);
630 
631  #ifdef _STUN_DEBUG
632  details::dump_buffer("STUN <<< ", bytes);
633  #endif
634 
635  return decoder::decode_message(bytes, nullptr);
636 }
637 
638 void client::verbose(char const * format, ...)
639 {
640  if (!m_verbose)
641  return;
642  va_list ap;
643  va_start(ap, format);
644  printf("STUN:");
645  vprintf(format, ap);
646  va_end(ap);
647 }
648 
649 network_access_type client::discover_network_access_type(server const & srv)
650 {
651  std::chrono::milliseconds wait_time(250);
652  std::vector<sockaddr_storage> addrs = details::resolve_hostname(srv.hostname, srv.port, m_protocol);
653 
654  sockaddr_storage server_addr = {};
655 
656  std::unique_ptr<message> binding_response;
657  for (sockaddr_storage const & addr : addrs) {
658  binding_response = this->send_binding_request(addr, wait_time);
659  if (binding_response) {
660  server_addr = addr;
661  break;
662  }
663  else
664  wait_time = std::min(wait_time * 2, details::binding_requests_wait_time_max);
665  }
666 
667  if (!binding_response)
668  return network_access_type::udp_blocked;
669 
670  // get endpoint binding_request was sent from and compare to the binding_response
671  // if they're the same, run "test II".
672  sockaddr_storage local_endpoint;
673  socklen_t socklen = sizeof(sockaddr_storage);
674  int ret = getsockname(m_fd, reinterpret_cast<sockaddr *>(&local_endpoint), &socklen);
675  if (ret == -1)
676  details::throw_error("failed to get local socket name:%s", strerror(errno));
677 
678  local_endpoint.ss_family = AF_INET;
679  std::string s = sockaddr_to_string(local_endpoint);
680 
681  return network_access_type::unknown;
682 }
683 
684 std::unique_ptr<message> client::send_binding_request(std::chrono::milliseconds wait_time)
685 {
686  std::unique_ptr<message> binding_response;
687  std::vector<sockaddr_storage> addrs = details::resolve_hostname(m_server.hostname, m_server.port, m_protocol);
688  for (sockaddr_storage const & addr : addrs) {
689  binding_response = this->send_binding_request(addr, wait_time);
690  if (binding_response)
691  break;
692  else
693  wait_time = std::min(wait_time * 2, details::binding_requests_wait_time_max);
694  }
695  return binding_response;
696 }
697 
698 std::unique_ptr<message> client::send_binding_request(sockaddr_storage const & addr,
699  std::chrono::milliseconds wait_time)
700 {
701  this->verbose("sending binding request with wait time:%lld ms\n", wait_time.count());
702  this->create_udp_socket(addr.ss_family);
703  std::unique_ptr<message> binding_request(message_factory::create_binding_request());
704  std::unique_ptr<message> binding_response(this->send_message(addr, *binding_request, wait_time));
705  return binding_response;
706 }
707 
708 attributes::address::address(attribute const & attr)
709 {
710  size_t offset = 0;
711 
712  // the family is actually 8-bits, but the pkt has a 1 byte padding
713  // for alignment
714  uint16_t family = decoder::decode_u16(attr.value, &offset);
715  if (family == 1) {
716  sockaddr_in * v4 = reinterpret_cast<sockaddr_in *>(&m_addr);
717  v4->sin_port = decoder::decode_u16(attr.value, &offset);
718  v4->sin_addr.s_addr = htonl(decoder::decode_u32(attr.value, &offset));
719  m_addr = * reinterpret_cast<sockaddr_storage *>(v4);
720  m_addr.ss_family = AF_INET;
721  }
722  else if (family == 2) {
723  sockaddr_in6 * v6 = reinterpret_cast<sockaddr_in6 *>(&m_addr);
724  v6->sin6_port = decoder::decode_u16(attr.value, &offset);
725  for (int i = 0; i < 16; ++i)
726  v6->sin6_addr.s6_addr[i] = attr.value[offset + i];
727  m_addr = * reinterpret_cast<sockaddr_storage *>(v6);
728  m_addr.ss_family = AF_INET6;
729  }
730  else
731  details::throw_error("invalid mapped address family:%d", family);
732 }
733 
734 uint32_t decoder::decode_u32(buffer const & buff, size_t * offset)
735 {
736  uint32_t const * p = reinterpret_cast<uint32_t const *>(&buff[*offset]);
737  uint32_t value = ntohl(*p);
738  *offset += 4;
739  return value;
740 }
741 
742 uint16_t decoder::decode_u16(buffer const & buff, size_t * offset)
743 {
744  uint16_t const * p = reinterpret_cast<uint16_t const *>(&buff[*offset]);
745  uint16_t value = ntohs(*p);
746  *offset += 2;
747  return value;
748 }
749 
750 message * decoder::decode_message(buffer const & buff, size_t * offset)
751 {
752  size_t temp_offset = 0;
753  if (offset)
754  temp_offset = *offset;
755 
756  // TODO: use a factory
757  // create a map[ message_type ] = message_factory_method
758 
759  message * new_message = nullptr;
760  message_header header;
761  header.message_type = decoder::decode_u16(buff, &temp_offset);
762  header.message_length = decoder::decode_u16(buff, &temp_offset);
763  if (header.message_type == message_type::binding_response) {
764  for (size_t i = 0, n = header.transaction_id.size(); i < n; ++i)
765  header.transaction_id[i] = buff[temp_offset++ + i];
766  new_message = new message();
767  new_message->m_header = header;
768  while (temp_offset < buff.size())
769  new_message->m_attrs.push_back(decoder::decode_attr(buff, &temp_offset));
770  }
771  else {
772  // TODO: unsupported message type
773  }
774 
775  if (offset)
776  *offset = temp_offset;
777 
778  return new_message;
779 }
780 
781 attribute decoder::decode_attr(buffer const & buff, size_t * offset)
782 {
783  attribute t = {};
784  t.type = decoder::decode_u16(buff, offset);
785  t.length = decoder::decode_u16(buff, offset);
786  t.value.insert(std::end(t.value), std::begin(buff) + *offset,
787  std::begin(buff) + *offset + t.length);
788  *offset += t.value.size();
789  return t;
790 }
791 
792 void encoder::encode_u16(buffer & buff, uint16_t n)
793 {
794  uint16_t temp = htons(n);
795  uint8_t * p = reinterpret_cast< uint8_t * >(&temp);
796  buff.push_back(p[0]);
797  buff.push_back(p[1]);
798 }
799 
800 void encoder::encode_u32(buffer & buff, uint32_t n)
801 {
802  uint32_t temp = htons(n);
803  uint8_t * p = reinterpret_cast<uint8_t *>(&temp);
804  buff.push_back(p[0]);
805  buff.push_back(p[1]);
806  buff.push_back(p[2]);
807  buff.push_back(p[3]);
808 }
809 
810 std::string sockaddr_to_string(sockaddr_storage const & addr)
811 {
812  sockaddr const * temp = reinterpret_cast<sockaddr const *>(&addr);
813  return details::sockaddr_to_string2(temp, addr.ss_family);
814 }
815 
816 } // end namespace stun
netsrvmgrIarm.h
The header file provides components netSrvMgrIarm information APIs.
stun::attributes::mapped_address
Definition: StunClient.h:72
netSrvMgrUtiles::getInterfaceConfig
bool getInterfaceConfig(const char *ifName, const unsigned int family, char *interfaceIp, char *netMask)
This function is used to get Interface IP address and on which interface.
Definition: netsrvmgrUtiles.cpp:481
dump_buffer
void dump_buffer(unsigned char *buf, int len)
This function is used to print the content of log buffer in hexadecimal format.
Definition: Util.cpp:142
netsrvmgrUtiles.h
The header file provides components netSrvMgrUtiles information APIs.
stun::details::file_descriptor
Definition: StunClient.cpp:45
IARM_BUS_NetSrvMgr_Iface_Settings_t
Definition: netsrvmgrIarm.h:114
stun::attribute
Definition: StunClient.h:56