Imported Upstream version 0.3.3
[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(u_int32_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(u_int32_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(u_int32_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     }
75     catch(const std::runtime_error& e)
76     {
77       onError_(e);
78     }
79   } else {
80     cLog.msg(Log::PRIO_ERROR) << "Error while resolving '" << addr_ << "' '" << port_ << "', retrying in 10 sec.";
81     boost::thread(boost::bind(waitAndEnqueue<Proto>, 10, addr_, port_, onResolve_, onError_, resolv_addr_type_));
82   }
83 }
84
85 Resolver* Resolver::inst = NULL;
86 Mutex Resolver::instMutex;
87 Resolver& gResolver = Resolver::instance();
88
89 Resolver& Resolver::instance()
90 {
91   Lock lock(instMutex);
92   static instanceCleaner c;
93   if(!inst)
94     inst = new Resolver();
95   
96   return *inst;
97 }
98
99 Resolver::Resolver() : udp_resolver_(io_service_), tcp_resolver_(io_service_), thread_(NULL)
100 {
101 }
102
103 Resolver::~Resolver()
104 {
105   if(thread_)
106     delete thread_;
107 }
108
109 void Resolver::init()
110 {
111   if(!thread_)
112           thread_ = new boost::thread(boost::bind(&Resolver::run, this));
113 }
114
115 void Resolver::run()
116 {
117   cLog.msg(Log::PRIO_DEBUG) << "Resolver Thread started";
118
119   while(1) {
120     try {
121       io_service_.run();
122       io_service_.reset();
123       boost::this_thread::sleep(boost::posix_time::milliseconds(250));
124     }
125     catch(const std::runtime_error& e)
126     {
127       cLog.msg(Log::PRIO_ERROR) << "resolver caught runtime error, restarting: " << e.what();
128     }
129     catch(const std::exception& e)
130     {
131       cLog.msg(Log::PRIO_ERROR) << "resolver caught exception, restarting: " << e.what();
132     }
133   }
134 }
135
136
137 void Resolver::resolveUdp(const std::string& addr, const std::string& port, UdpResolveCallback const& onResolve, ErrorCallback const& onError, ResolvAddrType r)
138 {
139   cLog.msg(Log::PRIO_DEBUG) << "trying to resolv UDP: '" << addr << "' '" << port << "'";
140
141   std::auto_ptr<udp::resolver::query> query;
142   if(addr != "") {
143     switch(r) {
144     case IPV4_ONLY: query = std::auto_ptr<udp::resolver::query>(new udp::resolver::query(udp::v4(), addr, port)); break;
145     case IPV6_ONLY: query = std::auto_ptr<udp::resolver::query>(new udp::resolver::query(udp::v6(), addr, port)); break;
146     default: query = std::auto_ptr<udp::resolver::query>(new udp::resolver::query(addr, port)); break;
147     }
148   }
149   else {
150     switch(r) {
151     case IPV4_ONLY: query = std::auto_ptr<udp::resolver::query>(new udp::resolver::query(udp::v4(), port)); break;
152     case IPV6_ONLY: query = std::auto_ptr<udp::resolver::query>(new udp::resolver::query(udp::v6(), port)); break;
153     default: query = std::auto_ptr<udp::resolver::query>(new udp::resolver::query(port)); break;
154     }
155   }
156   UdpResolveHandler handler(addr, port, onResolve, onError, r);
157   udp_resolver_.async_resolve(*query, handler);
158 }
159
160 void Resolver::resolveTcp(const std::string& addr, const std::string& port, TcpResolveCallback const& onResolve, ErrorCallback const& onError, ResolvAddrType r)
161 {
162   cLog.msg(Log::PRIO_DEBUG) << "trying to resolv TCP: '" << addr << "' '" << port << "'";
163
164   std::auto_ptr<tcp::resolver::query> query;
165   if(addr != "") {
166     switch(r) {
167     case IPV4_ONLY: query = std::auto_ptr<tcp::resolver::query>(new tcp::resolver::query(tcp::v4(), addr, port)); break;
168     case IPV6_ONLY: query = std::auto_ptr<tcp::resolver::query>(new tcp::resolver::query(tcp::v6(), addr, port)); break;
169     default: query = std::auto_ptr<tcp::resolver::query>(new tcp::resolver::query(addr, port)); break;
170     }
171   }
172   else {
173     switch(r) {
174     case IPV4_ONLY: query = std::auto_ptr<tcp::resolver::query>(new tcp::resolver::query(tcp::v4(), port)); break;
175     case IPV6_ONLY: query = std::auto_ptr<tcp::resolver::query>(new tcp::resolver::query(tcp::v6(), port)); break;
176     default: query = std::auto_ptr<tcp::resolver::query>(new tcp::resolver::query(port)); break;
177     }
178   }
179   TcpResolveHandler handler(addr, port, onResolve, onError, r);
180   tcp_resolver_.async_resolve(*query, handler); 
181 }