OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
bind_resolver.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include <boost/bind.hpp>
6 #include <bind/bind_util.h>
7 #include <base/address_util.h>
8 #include <bind/bind_resolver.h>
9 
11 
12 void BindResolver::Init(boost::asio::io_context &io,
13  const std::vector<DnsServer> &dns_servers,
14  uint16_t client_port, Callback cb, uint8_t dscp) {
15  assert(resolver_ == NULL);
16  resolver_ = new BindResolver(io, dns_servers, client_port, cb, dscp);
17 }
18 
20  if (resolver_) {
21  delete resolver_;
22  resolver_ = NULL;
23  }
24 }
25 
26 BindResolver::BindResolver(boost::asio::io_context &io,
27  const std::vector<DnsServer> &dns_servers,
28  uint16_t client_port, Callback cb,
29  uint8_t dscp)
30  : pkt_buf_(NULL), cb_(cb), sock_(io), dscp_value_(dscp) {
31 
32  boost::system::error_code ec;
33  uint8_t size = (dns_servers.size() > max_dns_servers) ?
34  dns_servers.size() : max_dns_servers;
35  dns_ep_.resize(size);
36  for (unsigned int i = 0; i < dns_servers.size(); ++i) {
37  boost::asio::ip::address dns_address(
38  AddressFromString(dns_servers[i].ip_, &ec));
39  boost::asio::ip::udp::endpoint *ep =
40  new boost::asio::ip::udp::endpoint(dns_address, dns_servers[i].port_);
41  assert (ec.value() == 0);
42  dns_ep_[i] = ep;
43  }
44 
45  boost::asio::ip::udp::endpoint local_ep(boost::asio::ip::address::
46  from_string("0.0.0.0", ec),
47  client_port);
48  sock_.open(boost::asio::ip::udp::v4(), ec);
49  assert(ec.value() == 0);
50  sock_.bind(local_ep, ec);
51  if (ec.value() != 0) {
52  local_ep.port(0);
53  sock_.bind(local_ep, ec);
54  assert(ec.value() == 0);
55  }
56  if (dscp_value_) {
58  }
59  AsyncRead();
60 }
61 
63  /* The dscp_value_ field is expected to have DSCP value between 0 and 63 ie
64  * in the lower order 6 bits of a byte. However, setsockopt expects DSCP
65  * value in upper 6 bits of a byte. Hence left shift the value by 2 digits
66  * before passing it to setsockopt */
67  uint8_t value = dscp_value_ << 2;
68  int retval = setsockopt(sock_.native_handle(), IPPROTO_IP, IP_TOS,
69  reinterpret_cast<const char *>(&value), sizeof(value));
70  if (retval < 0) {
71  DNS_BIND_TRACE(DnsBindError, "Setting DSCP bits on socket failed for "
72  << dscp_value_ << " with errno " << strerror(errno));
73  }
74 }
75 
76 void BindResolver::SetDscpValue(uint8_t val) {
77  dscp_value_ = val;
79 }
80 
82  uint8_t dscp = 0;
83  unsigned int optlen = sizeof(dscp);
84  int retval = getsockopt(sock_.native_handle(), IPPROTO_IP, IP_TOS,
85  reinterpret_cast<char *>(&dscp),
86  reinterpret_cast<socklen_t *>(&optlen));
87  if (retval < 0) {
88  DNS_BIND_TRACE(DnsBindError, "Getting DSCP bits on socket failed "
89  "with errno " << strerror(errno));
90  }
91  return dscp;
92 }
93 
95  boost::system::error_code ec;
96  sock_.cancel(ec);
97  sock_.close(ec);
98  for (unsigned int i = 0; i < dns_ep_.size(); ++i) {
99  delete dns_ep_[i];
100  dns_ep_[i] = NULL;
101  }
102  resolver_ = NULL;
103  if (pkt_buf_) delete [] pkt_buf_;
104 }
105 
106 void BindResolver::SetupResolver(const DnsServer &server, uint8_t idx) {
107  if (idx >= max_dns_servers) {
108  DNS_BIND_TRACE(DnsBindError, "BindResolver doesnt support more than " <<
109  max_dns_servers << " servers; ignoring request for " <<
110  idx);
111  return;
112  }
113 
114  if (idx < dns_ep_.size() && dns_ep_[idx]) {
115  delete dns_ep_[idx];
116  dns_ep_[idx] = NULL;
117  }
118 
119  boost::system::error_code ec;
120  boost::asio::ip::udp::endpoint *ep = new boost::asio::ip::udp::endpoint(
121  AddressFromString(server.ip_, &ec), server.port_);
122  assert (ec.value() == 0);
123  dns_ep_[idx] = ep;
124 }
125 
126 bool BindResolver::DnsSend(uint8_t *pkt, unsigned int dns_srv_index,
127  std::size_t len) {
128  if (dns_srv_index < dns_ep_.size() && dns_ep_[dns_srv_index] && len > 0) {
129  sock_.async_send_to(
130  boost::asio::buffer(pkt, len), *dns_ep_[dns_srv_index],
131  boost::bind(&BindResolver::DnsSendHandler, this,
132  boost::asio::placeholders::error,
133  boost::asio::placeholders::bytes_transferred, pkt));
134  return true;
135  } else {
136  DNS_BIND_TRACE(DnsBindError, "Invalid server index: " << dns_srv_index
137  << ";");
138  delete [] pkt;
139  return false;
140  }
141 }
142 
143 bool BindResolver::DnsSend(uint8_t *pkt, boost::asio::ip::udp::endpoint ep,
144  std::size_t len) {
145  if (len > 0) {
146  sock_.async_send_to(
147  boost::asio::buffer(pkt, len),ep,
148  boost::bind(&BindResolver::DnsSendHandler, this,
149  boost::asio::placeholders::error,
150  boost::asio::placeholders::bytes_transferred, pkt));
151  return true;
152  } else {
153  DNS_BIND_TRACE(DnsBindError, "Invalid length of packet: " << len
154  << ";");
155  delete [] pkt;
156  return false;
157  }
158 }
159 
160 void BindResolver::DnsSendHandler(const boost::system::error_code &error,
161  std::size_t length, uint8_t *pkt) {
162  if (error)
163  DNS_BIND_TRACE(DnsBindError, "Error sending packet to DNS server : " <<
164  boost::system::system_error(error).what() << ";");
165  delete [] pkt;
166 }
167 
169  pkt_buf_ = new uint8_t[max_pkt_size];
170  sock_.async_receive(boost::asio::buffer(pkt_buf_, max_pkt_size),
171  boost::bind(&BindResolver::DnsRcvHandler, this,
172  boost::asio::placeholders::error,
173  boost::asio::placeholders::bytes_transferred));
174 }
175 
176 void BindResolver::DnsRcvHandler(const boost::system::error_code &error,
177  std::size_t length) {
178  bool del = false;
179  if (!error) {
180  if (cb_)
181  cb_(pkt_buf_, length);
182  else
183  del = true;
184  } else {
185  DNS_BIND_TRACE(DnsBindError, "Error receiving DNS response : " <<
186  boost::system::system_error(error).what() << ";");
187  if (error.value() == boost::asio::error::operation_aborted) {
188  return;
189  }
190  del = true;
191  }
192  if (del) delete [] pkt_buf_;
193  pkt_buf_ = NULL;
194  AsyncRead();
195 }
virtual ~BindResolver()
#define DNS_BIND_TRACE(obj, arg)
Definition: bind_util.h:21
boost::asio::ip::udp::socket sock_
Definition: bind_resolver.h:55
void SetDscpSocketOption()
static const int max_pkt_size
Definition: bind_resolver.h:17
BindResolver(boost::asio::io_context &io, const std::vector< DnsServer > &dns_servers, uint16_t client_port, Callback cb, uint8_t dscp)
void SetDscpValue(uint8_t val)
uint8_t * pkt_buf_
Definition: bind_resolver.h:53
uint8_t dscp_value_
Definition: bind_resolver.h:57
static const uint8_t max_dns_servers
Definition: bind_resolver.h:18
static BindResolver * resolver_
Definition: bind_resolver.h:58
bool DnsSend(uint8_t *pkt, unsigned int dns_srv_index, std::size_t len)
uint8_t GetDscpValue()
Callback cb_
Definition: bind_resolver.h:54
static void Shutdown()
void DnsSendHandler(const boost::system::error_code &error, std::size_t length, uint8_t *pkt)
void SetupResolver(const DnsServer &server, uint8_t idx)
std::vector< boost::asio::ip::udp::endpoint * > dns_ep_
Definition: bind_resolver.h:56
IpAddress AddressFromString(const std::string &ip_address_str, boost::system::error_code *ec)
void DnsRcvHandler(const boost::system::error_code &error, std::size_t length)
static void Init(boost::asio::io_context &io, const std::vector< DnsServer > &dns_servers, uint16_t client_port, Callback cb, uint8_t dscp)
boost::function< void(uint8_t *, std::size_t)> Callback
Definition: bind_resolver.h:16