Used a more uniform of logging and added a commandline parser.
[UnsignedByte.git] / src / Sockets / ResolvSocket.cpp
blob5dcb94ecec9d6049c09b1c170fee5dd08dcd6cba
1 /** \file ResolvSocket.cpp
2 ** \date 2005-03-24
3 ** \author grymse@alhem.net
4 **/
5 /*
6 Copyright (C) 2004-2007 Anders Hedstrom
8 This library is made available under the terms of the GNU GPL.
10 If you would like to use this library in a closed-source application,
11 a separate license agreement is available. For information about
12 the closed-source license agreement for the C++ sockets library,
13 please visit http://www.alhem.net/Sockets/license.html and/or
14 email license@alhem.net.
16 This program is free software; you can redistribute it and/or
17 modify it under the terms of the GNU General Public License
18 as published by the Free Software Foundation; either version 2
19 of the License, or (at your option) any later version.
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifdef _WIN32
31 #ifndef __MINGW32__
32 #pragma warning(disable:4786)
33 #pragma warning(disable:4503)
34 #endif
35 #else
36 #include <netdb.h>
37 #endif
38 #include "ResolvSocket.h"
39 #ifdef ENABLE_RESOLVER
40 #include "Utility.h"
41 #include "Parse.h"
42 #include "ISocketHandler.h"
43 #include "Lock.h"
45 #ifdef SOCKETS_NAMESPACE
46 namespace SOCKETS_NAMESPACE {
47 #endif
49 #ifdef _DEBUG
50 #define DEB(x) x
51 #else
52 #define DEB(x)
53 #endif
56 // static
57 ResolvSocket::cache_t ResolvSocket::m_cache;
58 ResolvSocket::timeout_t ResolvSocket::m_cache_to;
59 Mutex ResolvSocket::m_cache_mutex;
62 ResolvSocket::ResolvSocket(ISocketHandler& h)
63 :TcpSocket(h)
64 ,m_bServer(false)
65 ,m_parent(NULL)
66 #ifdef ENABLE_IPV6
67 ,m_resolve_ipv6(false)
68 #endif
69 ,m_cached(false)
71 SetLineProtocol();
75 ResolvSocket::ResolvSocket(ISocketHandler& h, Socket *parent, const std::string& host, port_t port, bool ipv6)
76 :TcpSocket(h)
77 ,m_bServer(false)
78 ,m_parent(parent)
79 ,m_resolv_host(host)
80 ,m_resolv_port(port)
81 #ifdef ENABLE_IPV6
82 ,m_resolve_ipv6(ipv6)
83 #endif
84 ,m_cached(false)
86 SetLineProtocol();
90 ResolvSocket::ResolvSocket(ISocketHandler& h, Socket *parent, ipaddr_t a)
91 :TcpSocket(h)
92 ,m_bServer(false)
93 ,m_parent(parent)
94 ,m_resolv_port(0)
95 ,m_resolv_address(a)
96 #ifdef ENABLE_IPV6
97 ,m_resolve_ipv6(false)
98 #endif
99 ,m_cached(false)
101 SetLineProtocol();
105 #ifdef ENABLE_IPV6
106 ResolvSocket::ResolvSocket(ISocketHandler& h, Socket *parent, in6_addr& a)
107 :TcpSocket(h)
108 ,m_bServer(false)
109 ,m_parent(parent)
110 ,m_resolv_port(0)
111 ,m_resolve_ipv6(true)
112 ,m_resolv_address6(a)
113 ,m_cached(false)
115 SetLineProtocol();
117 #endif
120 ResolvSocket::~ResolvSocket()
125 void ResolvSocket::OnLine(const std::string& line)
127 Parse pa(line, ":");
128 if (m_bServer)
130 m_query = pa.getword();
131 m_data = pa.getrest();
132 DEB( fprintf(stderr, "ResolvSocket server; query=%s, data=%s\n", m_query.c_str(), m_data.c_str());)
133 // %! check cache
135 Lock lock(m_cache_mutex);
136 if (m_cache[m_query].find(m_data) != m_cache[m_query].end())
138 if (time(NULL) - m_cache_to[m_query][m_data] < 3600) // ttl
140 std::string result = m_cache[m_query][m_data];
141 DEB(printf("Returning cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), result.c_str());)
142 Send("Cached\n");
143 if (!result.size()) /* failed */
145 Send("Failed\n\n");
146 SetCloseAndDelete();
147 return;
149 else
150 if (m_query == "gethostbyname")
152 Send("A: " + result + "\n\n");
153 SetCloseAndDelete();
154 return;
156 else
157 #ifdef ENABLE_IPV6
158 #ifdef IPPROTO_IPV6
159 if (m_query == "gethostbyname2")
161 Send("AAAA: " + result + "\n\n");
162 SetCloseAndDelete();
163 return;
165 else
166 #endif
167 #endif
168 if (m_query == "gethostbyaddr")
170 Send("Name: " + result + "\n\n");
171 SetCloseAndDelete();
172 return;
177 if (!Detach()) // detach failed?
179 SetCloseAndDelete();
181 return;
183 std::string key = pa.getword();
184 std::string value = pa.getrest();
186 if (key == "Cached")
188 m_cached = true;
190 else
191 if (key == "Failed" && m_parent)
193 DEB( fprintf(stderr, "************ Resolve failed\n");)
194 if (Handler().Valid(m_parent))
196 m_parent -> OnResolveFailed(m_resolv_id);
198 // update cache
199 if (!m_cached)
201 Lock lock(m_cache_mutex);
202 DEB(printf("Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
203 m_cache[m_query][m_data] = value;
204 m_cache_to[m_query][m_data] = time(NULL);
206 m_parent = NULL;
208 else
209 if (key == "Name" && !m_resolv_host.size() && m_parent)
211 if (Handler().Valid(m_parent))
213 m_parent -> OnReverseResolved(m_resolv_id, value);
215 // update cache
216 if (!m_cached)
218 Lock lock(m_cache_mutex);
219 DEB(printf("Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
220 m_cache[m_query][m_data] = value;
221 m_cache_to[m_query][m_data] = time(NULL);
223 m_parent = NULL;
225 else
226 if (key == "A" && m_parent)
228 ipaddr_t l;
229 Utility::u2ip(value, l); // ip2ipaddr_t
230 if (Handler().Valid(m_parent))
232 m_parent -> OnResolved(m_resolv_id, l, m_resolv_port);
234 // update cache
235 if (!m_cached)
237 Lock lock(m_cache_mutex);
238 DEB(printf("Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
239 m_cache[m_query][m_data] = value;
240 m_cache_to[m_query][m_data] = time(NULL);
242 m_parent = NULL; // always use first ip in case there are several
244 #ifdef ENABLE_IPV6
245 #ifdef IPPROTO_IPV6
246 else
247 if (key == "AAAA" && m_parent)
249 in6_addr a;
250 Utility::u2ip(value, a);
251 if (Handler().Valid(m_parent))
253 m_parent -> OnResolved(m_resolv_id, a, m_resolv_port);
255 // update cache
256 if (!m_cached)
258 Lock lock(m_cache_mutex);
259 DEB(printf("Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
260 m_cache[m_query][m_data] = value;
261 m_cache_to[m_query][m_data] = time(NULL);
263 m_parent = NULL;
265 #endif
266 #endif
270 void ResolvSocket::OnDetached()
272 DEB( fprintf(stderr, "ResolvSocket::OnDetached(); query=%s, data=%s\n", m_query.c_str(), m_data.c_str());)
273 if (m_query == "gethostbyname")
275 struct sockaddr_in sa;
276 if (Utility::u2ip(m_data, sa))
278 std::string ip;
279 Utility::l2ip(sa.sin_addr, ip);
280 Send("A: " + ip + "\n");
282 else
284 Send("Failed\n");
286 Send("\n");
288 else
289 #ifdef ENABLE_IPV6
290 #ifdef IPPROTO_IPV6
291 if (m_query == "gethostbyname2")
293 struct sockaddr_in6 sa;
294 if (Utility::u2ip(m_data, sa))
296 std::string ip;
297 Utility::l2ip(sa.sin6_addr, ip);
298 Send("AAAA: " + ip + "\n");
300 else
302 Send("Failed\n");
304 Send("\n");
306 else
307 #endif
308 #endif
309 if (m_query == "gethostbyaddr")
311 if (Utility::isipv4( m_data ))
313 struct sockaddr_in sa;
314 if (!Utility::u2ip(m_data, sa, AI_NUMERICHOST))
316 Send("Failed: convert to sockaddr_in failed\n");
318 else
320 std::string name;
321 if (!Utility::reverse( (struct sockaddr *)&sa, sizeof(sa), name))
323 Send("Failed: ipv4 reverse lookup of " + m_data + "\n");
325 else
327 Send("Name: " + name + "\n");
331 else
332 #ifdef ENABLE_IPV6
333 #ifdef IPPROTO_IPV6
334 if (Utility::isipv6( m_data ))
336 struct sockaddr_in6 sa;
337 if (!Utility::u2ip(m_data, sa, AI_NUMERICHOST))
339 Send("Failed: convert to sockaddr_in6 failed\n");
341 else
343 std::string name;
344 if (!Utility::reverse( (struct sockaddr *)&sa, sizeof(sa), name))
346 Send("Failed: ipv6 reverse lookup of " + m_data + "\n");
348 else
350 Send("Name: " + name + "\n");
354 else
355 #endif
356 #endif
358 Send("Failed: malformed address\n");
360 Send("\n");
362 else
364 std::string msg = "Unknown query type: " + m_query;
365 Handler().LogError(this, "OnDetached", 0, msg);
366 Send("Unknown\n\n");
368 SetCloseAndDelete();
372 void ResolvSocket::OnConnect()
374 if (m_resolv_host.size())
376 #ifdef ENABLE_IPV6
377 std::string msg = (m_resolve_ipv6 ? "gethostbyname2 " : "gethostbyname ") + m_resolv_host + "\n";
378 m_query = m_resolve_ipv6 ? "gethostbyname2" : "gethostbyname";
379 #else
380 std::string msg = "gethostbyname " + m_resolv_host + "\n";
381 m_query = "gethostbyname";
382 #endif
383 m_data = m_resolv_host;
384 Send( msg );
385 return;
387 #ifdef ENABLE_IPV6
388 if (m_resolve_ipv6)
390 std::string tmp;
391 Utility::l2ip(m_resolv_address6, tmp);
392 m_query = "gethostbyaddr";
393 m_data = tmp;
394 std::string msg = "gethostbyaddr " + tmp + "\n";
395 Send( msg );
397 #endif
398 std::string tmp;
399 Utility::l2ip(m_resolv_address, tmp);
400 m_query = "gethostbyaddr";
401 m_data = tmp;
402 std::string msg = "gethostbyaddr " + tmp + "\n";
403 Send( msg );
407 void ResolvSocket::OnDelete()
409 if (m_parent)
411 if (Handler().Valid(m_parent))
413 m_parent -> OnResolveFailed(m_resolv_id);
415 // update cache
416 if (!m_cached)
418 Lock lock(m_cache_mutex);
419 std::string value;
420 DEB(printf("Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
421 m_cache[m_query][m_data] = value;
422 m_cache_to[m_query][m_data] = time(NULL);
424 m_parent = NULL;
429 #ifdef SOCKETS_NAMESPACE
431 #endif
433 #endif // ENABLE_RESOLVER