Imported Upstream version 0.3.4
[anytun.git] / src / resolver.cpp
1 /*
2  *  anytun
3  *
4  *  The secure anycast tunneling protocol (satp) defines a protocol used
5  *  for communication between any combination of unicast and anycast
6  *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel
7  *  mode and allows tunneling of every ETHER TYPE protocol (e.g.
8  *  ethernet, ip, arp ...). satp directly includes cryptography and
9  *  message authentication based on the methodes used by SRTP.  It is
10  *  intended to deliver a generic, scaleable and secure solution for
11  *  tunneling and relaying of packets of any protocol.
12  *
13  *
14  *  Copyright (C) 2007-2009 Othmar Gsenger, Erwin Nindl,
15  *                          Christian Pointner <satp@wirdorange.org>
16  *
17  *  This file is part of Anytun.
18  *
19  *  Anytun is free software: you can redistribute it and/or modify
20  *  it under the terms of the GNU General Public License as published by
21  *  the Free Software Foundation, either version 3 of the License, or
22  *  any later version.
23  *
24  *  Anytun is distributed in the hope that it will be useful,
25  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
26  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  *  GNU General Public License for more details.
28  *
29  *  You should have received a copy of the GNU General Public License
30  *  along with anytun.  If not, see <http://www.gnu.org/licenses/>.
31  */
32
33 #include <boost/bind.hpp>
34 #include <boost/system/error_code.hpp>
35
36 #include "resolver.h"
37 #include "log.h"
38
39 using ::boost::asio::ip::udp;
40 using ::boost::asio::ip::tcp;
41
42 template<class Proto>
43 void waitAndEnqueue(uint32_t s, const std::string& addr, const std::string& port, boost::function<void(boost::asio::ip::basic_resolver_iterator<Proto>)> const& onResolve, ErrorCallback const& onError, ResolvAddrType r)
44 {
45   cLog.msg(Log::PRIO_ERROR) << "the resolver only supports udp and tcp";
46 }
47
48 template<>
49 void waitAndEnqueue(uint32_t s, const std::string& addr, const std::string& port, boost::function<void(boost::asio::ip::basic_resolver_iterator<udp>)> const& onResolve, ErrorCallback const& onError, ResolvAddrType r)
50 {
51   boost::this_thread::sleep(boost::posix_time::milliseconds(s * 1000));
52   gResolver.resolveUdp(addr, port, onResolve, onError, r);
53 }
54
55 template<>
56 void waitAndEnqueue(uint32_t s, const std::string& addr, const std::string& port, boost::function<void(boost::asio::ip::basic_resolver_iterator<tcp>)> const& onResolve, ErrorCallback const& onError, ResolvAddrType r)
57 {
58   boost::this_thread::sleep(boost::posix_time::milliseconds(s * 1000));
59   gResolver.resolveTcp(addr, port, onResolve, onError, r);
60 }
61
62
63 template<class Proto>
64 ResolveHandler<Proto>::ResolveHandler(const std::string& addr, const std::string& port, boost::function<void(boost::asio::ip::basic_resolver_iterator<Proto>)> const& onResolve, ErrorCallback const& onError, ResolvAddrType r) : addr_(addr), port_(port), onResolve_(onResolve), onError_(onError), resolv_addr_type_(r)
65 {
66 }
67
68 template<class Proto>
69 void ResolveHandler<Proto>::operator()(const boost::system::error_code& e, boost::asio::ip::basic_resolver_iterator<Proto> endpointIt)
70 {
71   if(boost::system::posix_error::success == e) {
72     try {
73       onResolve_(endpointIt);
74     } catch(const std::runtime_error& e) {
75       onError_(e);
76     }
77   } else {
78     cLog.msg(Log::PRIO_ERROR) << "Error while resolving '" << addr_ << "' '" << port_ << "', retrying in 10 sec.";
79     boost::thread(boost::bind(waitAndEnqueue<Proto>, 10, addr_, port_, onResolve_, onError_, resolv_addr_type_));
80   }
81 }
82
83 Resolver* Resolver::inst = NULL;
84 Mutex Resolver::instMutex;
85 Resolver& gResolver = Resolver::instance();
86
87 Resolver& Resolver::instance()
88 {
89   Lock lock(instMutex);
90   static instanceCleaner c;
91   if(!inst) {
92     inst = new Resolver();
93   }
94
95   return *inst;
96 }
97
98 Resolver::Resolver() : udp_resolver_(io_service_), tcp_resolver_(io_service_), thread_(NULL)
99 {
100 }
101
102 Resolver::~Resolver()
103 {
104   if(thread_) {
105     delete thread_;
106   }
107 }
108
109 void Resolver::init()
110 {
111   if(!thread_) {
112     thread_ = new boost::thread(boost::bind(&Resolver::run, this));
113   }
114 }
115
116 void Resolver::run()
117 {
118   cLog.msg(Log::PRIO_DEBUG) << "Resolver Thread started";
119
120   while(1) {
121     try {
122       io_service_.run();
123       io_service_.reset();
124       boost::this_thread::sleep(boost::posix_time::milliseconds(250));
125     } catch(const std::runtime_error& e) {
126       cLog.msg(Log::PRIO_ERROR) << "resolver caught runtime error, restarting: " << e.what();
127     } catch(const std::exception& e) {
128       cLog.msg(Log::PRIO_ERROR) << "resolver caught exception, restarting: " << e.what();
129     }
130   }
131 }
132
133
134 void Resolver::resolveUdp(const std::string& addr, const std::string& port, UdpResolveCallback const& onResolve, ErrorCallback const& onError, ResolvAddrType r)
135 {
136   cLog.msg(Log::PRIO_DEBUG) << "trying to resolv UDP: '" << addr << "' '" << port << "'";
137
138   std::auto_ptr<udp::resolver::query> query;
139   if(addr != "") {
140     switch(r) {
141     case IPV4_ONLY:
142       query = std::auto_ptr<udp::resolver::query>(new udp::resolver::query(udp::v4(), addr, port));
143       break;
144     case IPV6_ONLY:
145       query = std::auto_ptr<udp::resolver::query>(new udp::resolver::query(udp::v6(), addr, port));
146       break;
147     default:
148       query = std::auto_ptr<udp::resolver::query>(new udp::resolver::query(addr, port));
149       break;
150     }
151   } else {
152     switch(r) {
153     case IPV4_ONLY:
154       query = std::auto_ptr<udp::resolver::query>(new udp::resolver::query(udp::v4(), port));
155       break;
156     case IPV6_ONLY:
157       query = std::auto_ptr<udp::resolver::query>(new udp::resolver::query(udp::v6(), port));
158       break;
159     default:
160       query = std::auto_ptr<udp::resolver::query>(new udp::resolver::query(port));
161       break;
162     }
163   }
164   UdpResolveHandler handler(addr, port, onResolve, onError, r);
165   udp_resolver_.async_resolve(*query, handler);
166 }
167
168 void Resolver::resolveTcp(const std::string& addr, const std::string& port, TcpResolveCallback const& onResolve, ErrorCallback const& onError, ResolvAddrType r)
169 {
170   cLog.msg(Log::PRIO_DEBUG) << "trying to resolv TCP: '" << addr << "' '" << port << "'";
171
172   std::auto_ptr<tcp::resolver::query> query;
173   if(addr != "") {
174     switch(r) {
175     case IPV4_ONLY:
176       query = std::auto_ptr<tcp::resolver::query>(new tcp::resolver::query(tcp::v4(), addr, port));
177       break;
178     case IPV6_ONLY:
179       query = std::auto_ptr<tcp::resolver::query>(new tcp::resolver::query(tcp::v6(), addr, port));
180       break;
181     default:
182       query = std::auto_ptr<tcp::resolver::query>(new tcp::resolver::query(addr, port));
183       break;
184     }
185   } else {
186     switch(r) {
187     case IPV4_ONLY:
188       query = std::auto_ptr<tcp::resolver::query>(new tcp::resolver::query(tcp::v4(), port));
189       break;
190     case IPV6_ONLY:
191       query = std::auto_ptr<tcp::resolver::query>(new tcp::resolver::query(tcp::v6(), port));
192       break;
193     default:
194       query = std::auto_ptr<tcp::resolver::query>(new tcp::resolver::query(port));
195       break;
196     }
197   }
198   TcpResolveHandler handler(addr, port, onResolve, onError, r);
199   tcp_resolver_.async_resolve(*query, handler);
200 }