1 /** \file ResolvSocket.cpp
3 ** \author grymse@alhem.net
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.
32 #pragma warning(disable:4786)
33 #pragma warning(disable:4503)
38 #include "ResolvSocket.h"
39 #ifdef ENABLE_RESOLVER
42 #include "ISocketHandler.h"
45 #ifdef SOCKETS_NAMESPACE
46 namespace SOCKETS_NAMESPACE
{
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
)
67 ,m_resolve_ipv6(false)
75 ResolvSocket::ResolvSocket(ISocketHandler
& h
, Socket
*parent
, const std::string
& host
, port_t port
, bool ipv6
)
90 ResolvSocket::ResolvSocket(ISocketHandler
& h
, Socket
*parent
, ipaddr_t a
)
97 ,m_resolve_ipv6(false)
106 ResolvSocket::ResolvSocket(ISocketHandler
& h
, Socket
*parent
, in6_addr
& a
)
111 ,m_resolve_ipv6(true)
112 ,m_resolv_address6(a
)
120 ResolvSocket::~ResolvSocket()
125 void ResolvSocket::OnLine(const std::string
& line
)
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());)
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());)
143 if (!result
.size()) /* failed */
150 if (m_query
== "gethostbyname")
152 Send("A: " + result
+ "\n\n");
159 if (m_query
== "gethostbyname2")
161 Send("AAAA: " + result
+ "\n\n");
168 if (m_query
== "gethostbyaddr")
170 Send("Name: " + result
+ "\n\n");
177 if (!Detach()) // detach failed?
183 std::string key
= pa
.getword();
184 std::string value
= pa
.getrest();
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
);
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
);
209 if (key
== "Name" && !m_resolv_host
.size() && m_parent
)
211 if (Handler().Valid(m_parent
))
213 m_parent
-> OnReverseResolved(m_resolv_id
, value
);
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
);
226 if (key
== "A" && m_parent
)
229 Utility::u2ip(value
, l
); // ip2ipaddr_t
230 if (Handler().Valid(m_parent
))
232 m_parent
-> OnResolved(m_resolv_id
, l
, m_resolv_port
);
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
247 if (key
== "AAAA" && m_parent
)
250 Utility::u2ip(value
, a
);
251 if (Handler().Valid(m_parent
))
253 m_parent
-> OnResolved(m_resolv_id
, a
, m_resolv_port
);
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
);
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
))
279 Utility::l2ip(sa
.sin_addr
, ip
);
280 Send("A: " + ip
+ "\n");
291 if (m_query
== "gethostbyname2")
293 struct sockaddr_in6 sa
;
294 if (Utility::u2ip(m_data
, sa
))
297 Utility::l2ip(sa
.sin6_addr
, ip
);
298 Send("AAAA: " + ip
+ "\n");
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");
321 if (!Utility::reverse( (struct sockaddr
*)&sa
, sizeof(sa
), name
))
323 Send("Failed: ipv4 reverse lookup of " + m_data
+ "\n");
327 Send("Name: " + name
+ "\n");
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");
344 if (!Utility::reverse( (struct sockaddr
*)&sa
, sizeof(sa
), name
))
346 Send("Failed: ipv6 reverse lookup of " + m_data
+ "\n");
350 Send("Name: " + name
+ "\n");
358 Send("Failed: malformed address\n");
364 std::string msg
= "Unknown query type: " + m_query
;
365 Handler().LogError(this, "OnDetached", 0, msg
);
372 void ResolvSocket::OnConnect()
374 if (m_resolv_host
.size())
377 std::string msg
= (m_resolve_ipv6
? "gethostbyname2 " : "gethostbyname ") + m_resolv_host
+ "\n";
378 m_query
= m_resolve_ipv6
? "gethostbyname2" : "gethostbyname";
380 std::string msg
= "gethostbyname " + m_resolv_host
+ "\n";
381 m_query
= "gethostbyname";
383 m_data
= m_resolv_host
;
391 Utility::l2ip(m_resolv_address6
, tmp
);
392 m_query
= "gethostbyaddr";
394 std::string msg
= "gethostbyaddr " + tmp
+ "\n";
399 Utility::l2ip(m_resolv_address
, tmp
);
400 m_query
= "gethostbyaddr";
402 std::string msg
= "gethostbyaddr " + tmp
+ "\n";
407 void ResolvSocket::OnDelete()
411 if (Handler().Valid(m_parent
))
413 m_parent
-> OnResolveFailed(m_resolv_id
);
418 Lock
lock(m_cache_mutex
);
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
);
429 #ifdef SOCKETS_NAMESPACE
433 #endif // ENABLE_RESOLVER