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