root/trunk/dep/src/sockets/ResolvSocket.cpp @ 2

Revision 2, 9.4 kB (checked in by yumileroy, 17 years ago)

[svn] * Proper SVN structure

Original author: Neo2003
Date: 2008-10-02 16:23:55-05:00

Line 
1/** \file ResolvSocket.cpp
2 **     \date  2005-03-24
3 **     \author grymse@alhem.net
4**/
5/*
6Copyright (C) 2004-2007  Anders Hedstrom
7
8This library is made available under the terms of the GNU GPL.
9
10If you would like to use this library in a closed-source application,
11a separate license agreement is available. For information about
12the closed-source license agreement for the C++ sockets library,
13please visit http://www.alhem.net/Sockets/license.html and/or
14email license@alhem.net.
15
16This program is free software; you can redistribute it and/or
17modify it under the terms of the GNU General Public License
18as published by the Free Software Foundation; either version 2
19of the License, or (at your option) any later version.
20
21This program is distributed in the hope that it will be useful,
22but WITHOUT ANY WARRANTY; without even the implied warranty of
23MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24GNU General Public License for more details.
25
26You should have received a copy of the GNU General Public License
27along with this program; if not, write to the Free Software
28Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
29*/
30#ifdef _WIN32
31#ifdef _MSC_VER
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"
44#include "Mutex.h"
45
46#ifdef SOCKETS_NAMESPACE
47namespace SOCKETS_NAMESPACE {
48#endif
49
50//#ifdef _DEBUG
51//#define DEB(x) x
52//#else
53#define DEB(x)
54//#endif
55
56
57// static
58ResolvSocket::cache_t ResolvSocket::m_cache;
59ResolvSocket::timeout_t ResolvSocket::m_cache_to;
60Mutex ResolvSocket::m_cache_mutex;
61
62
63ResolvSocket::ResolvSocket(ISocketHandler& h)
64:TcpSocket(h)
65,m_bServer(false)
66,m_parent(NULL)
67#ifdef ENABLE_IPV6
68,m_resolve_ipv6(false)
69#endif
70,m_cached(false)
71{
72        SetLineProtocol();
73}
74
75
76ResolvSocket::ResolvSocket(ISocketHandler& h, Socket *parent, const std::string& host, port_t port, bool ipv6)
77:TcpSocket(h)
78,m_bServer(false)
79,m_parent(parent)
80,m_resolv_host(host)
81,m_resolv_port(port)
82#ifdef ENABLE_IPV6
83,m_resolve_ipv6(ipv6)
84#endif
85,m_cached(false)
86{
87        SetLineProtocol();
88}
89
90
91ResolvSocket::ResolvSocket(ISocketHandler& h, Socket *parent, ipaddr_t a)
92:TcpSocket(h)
93,m_bServer(false)
94,m_parent(parent)
95,m_resolv_port(0)
96,m_resolv_address(a)
97#ifdef ENABLE_IPV6
98,m_resolve_ipv6(false)
99#endif
100,m_cached(false)
101{
102        SetLineProtocol();
103}
104
105
106#ifdef ENABLE_IPV6
107ResolvSocket::ResolvSocket(ISocketHandler& h, Socket *parent, in6_addr& a)
108:TcpSocket(h)
109,m_bServer(false)
110,m_parent(parent)
111,m_resolv_port(0)
112,m_resolve_ipv6(true)
113,m_resolv_address6(a)
114,m_cached(false)
115{
116        SetLineProtocol();
117}
118#endif
119
120
121ResolvSocket::~ResolvSocket()
122{
123}
124
125
126void ResolvSocket::OnLine(const std::string& line)
127{
128        Parse pa(line, ":");
129        if (m_bServer)
130        {
131                m_query = pa.getword();
132                m_data = pa.getrest();
133DEB(            fprintf(stderr, " *** ResolvSocket server; query=%s, data=%s\n", m_query.c_str(), m_data.c_str());)
134                // %! check cache
135                {
136                        Lock lock(m_cache_mutex);
137                        if (m_cache[m_query].find(m_data) != m_cache[m_query].end())
138                        {
139                                if (time(NULL) - m_cache_to[m_query][m_data] < 3600) // ttl
140                                {
141                                        std::string result = m_cache[m_query][m_data];
142DEB(fprintf(stderr, " *** Returning cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), result.c_str());)
143                                        Send("Cached\n");
144                                        if (!result.size()) /* failed */
145                                        {
146                                                Send("Failed\n\n");
147                                                SetCloseAndDelete();
148                                                return;
149                                        }
150                                        else
151                                        if (m_query == "gethostbyname")
152                                        {
153                                                Send("A: " + result + "\n\n");
154                                                SetCloseAndDelete();
155                                                return;
156                                        }
157                                        else
158#ifdef ENABLE_IPV6
159#ifdef IPPROTO_IPV6
160                                        if (m_query == "gethostbyname2")
161                                        {
162                                                Send("AAAA: " + result + "\n\n");
163                                                SetCloseAndDelete();
164                                                return;
165                                        }
166                                        else
167#endif
168#endif
169                                        if (m_query == "gethostbyaddr")
170                                        {
171                                                Send("Name: " + result + "\n\n");
172                                                SetCloseAndDelete();
173                                                return;
174                                        }
175                                }
176                        }
177                }
178                if (!Detach()) // detach failed?
179                {
180                        SetCloseAndDelete();
181                }
182                return;
183        }
184        std::string key = pa.getword();
185        std::string value = pa.getrest();
186DEB(    fprintf(stderr, " *** ResolvSocket response;  %s: %s\n", key.c_str(), value.c_str());)
187
188        if (key == "Cached")
189        {
190                m_cached = true;
191        }
192        else
193        if (key == "Failed" && m_parent)
194        {
195DEB(            fprintf(stderr, " ************ Resolve failed\n");)
196                if (Handler().Resolving(m_parent) || Handler().Valid(m_parent))
197                {
198                        m_parent -> OnResolveFailed(m_resolv_id);
199                }
200                // update cache
201                if (!m_cached)
202                {
203                        Lock lock(m_cache_mutex);
204DEB(fprintf(stderr, " *** Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
205                        m_cache[m_query][m_data] = value;
206                        m_cache_to[m_query][m_data] = time(NULL);
207                }
208                m_parent = NULL;
209        }
210        else
211        if (key == "Name" && !m_resolv_host.size() && m_parent)
212        {
213                if (Handler().Resolving(m_parent) || Handler().Valid(m_parent))
214                {
215                        m_parent -> OnReverseResolved(m_resolv_id, value);
216                }
217                // update cache
218                if (!m_cached)
219                {
220                        Lock lock(m_cache_mutex);
221DEB(fprintf(stderr, " *** Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
222                        m_cache[m_query][m_data] = value;
223                        m_cache_to[m_query][m_data] = time(NULL);
224                }
225                m_parent = NULL;
226        }
227        else
228        if (key == "A" && m_parent)
229        {
230                if (Handler().Resolving(m_parent) || Handler().Valid(m_parent))
231                {
232                        ipaddr_t l;
233                        Utility::u2ip(value, l); // ip2ipaddr_t
234                        m_parent -> OnResolved(m_resolv_id, l, m_resolv_port);
235                }
236                // update cache
237                if (!m_cached)
238                {
239                        Lock lock(m_cache_mutex);
240DEB(fprintf(stderr, " *** Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
241                        m_cache[m_query][m_data] = value;
242                        m_cache_to[m_query][m_data] = time(NULL);
243                }
244                m_parent = NULL; // always use first ip in case there are several
245        }
246#ifdef ENABLE_IPV6
247#ifdef IPPROTO_IPV6
248        else
249        if (key == "AAAA" && m_parent)
250        {
251                if (Handler().Resolving(m_parent) || Handler().Valid(m_parent))
252                {
253                        in6_addr a;
254                        Utility::u2ip(value, a);
255                        m_parent -> OnResolved(m_resolv_id, a, m_resolv_port);
256                }
257                // update cache
258                if (!m_cached)
259                {
260                        Lock lock(m_cache_mutex);
261DEB(fprintf(stderr, " *** Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
262                        m_cache[m_query][m_data] = value;
263                        m_cache_to[m_query][m_data] = time(NULL);
264                }
265                m_parent = NULL;
266        }
267#endif
268#endif
269}
270
271
272void ResolvSocket::OnDetached()
273{
274DEB(    fprintf(stderr, " *** ResolvSocket::OnDetached(); query=%s, data=%s\n", m_query.c_str(), m_data.c_str());)
275        if (m_query == "gethostbyname")
276        {
277                struct sockaddr_in sa;
278                if (Utility::u2ip(m_data, sa))
279                {
280                        std::string ip;
281                        Utility::l2ip(sa.sin_addr, ip);
282                        Send("A: " + ip + "\n");
283                }
284                else
285                {
286                        Send("Failed\n");
287                }
288                Send("\n");
289        }
290        else
291#ifdef ENABLE_IPV6
292#ifdef IPPROTO_IPV6
293        if (m_query == "gethostbyname2")
294        {
295                struct sockaddr_in6 sa;
296                if (Utility::u2ip(m_data, sa))
297                {
298                        std::string ip;
299                        Utility::l2ip(sa.sin6_addr, ip);
300                        Send("AAAA: " + ip + "\n");
301                }
302                else
303                {
304                        Send("Failed\n");
305                }
306                Send("\n");
307        }
308        else
309#endif
310#endif
311        if (m_query == "gethostbyaddr")
312        {
313                if (Utility::isipv4( m_data ))
314                {
315                        struct sockaddr_in sa;
316                        if (!Utility::u2ip(m_data, sa, AI_NUMERICHOST))
317                        {
318                                Send("Failed: convert to sockaddr_in failed\n");
319                        }
320                        else
321                        {
322                                std::string name;
323                                if (!Utility::reverse( (struct sockaddr *)&sa, sizeof(sa), name))
324                                {
325                                        Send("Failed: ipv4 reverse lookup of " + m_data + "\n");
326                                }
327                                else
328                                {
329                                        Send("Name: " + name + "\n");
330                                }
331                        }
332                }
333                else
334#ifdef ENABLE_IPV6
335#ifdef IPPROTO_IPV6
336                if (Utility::isipv6( m_data ))
337                {
338                        struct sockaddr_in6 sa;
339                        if (!Utility::u2ip(m_data, sa, AI_NUMERICHOST))
340                        {
341                                Send("Failed: convert to sockaddr_in6 failed\n");
342                        }
343                        else
344                        {
345                                std::string name;
346                                if (!Utility::reverse( (struct sockaddr *)&sa, sizeof(sa), name))
347                                {
348                                        Send("Failed: ipv6 reverse lookup of " + m_data + "\n");
349                                }
350                                else
351                                {
352                                        Send("Name: " + name + "\n");
353                                }
354                        }
355                }
356                else
357#endif
358#endif
359                {
360                        Send("Failed: malformed address\n");
361                }
362                Send("\n");
363        }
364        else
365        {
366                std::string msg = "Unknown query type: " + m_query;
367                Handler().LogError(this, "OnDetached", 0, msg);
368                Send("Unknown\n\n");
369        }
370        SetCloseAndDelete();
371}
372
373
374void ResolvSocket::OnConnect()
375{
376        if (!m_resolv_host.empty())
377        {
378#ifdef ENABLE_IPV6
379                std::string msg = (m_resolve_ipv6 ? "gethostbyname2 " : "gethostbyname ") + m_resolv_host + "\n";
380                m_query = m_resolve_ipv6 ? "gethostbyname2" : "gethostbyname";
381#else
382                std::string msg = "gethostbyname " + m_resolv_host + "\n";
383                m_query = "gethostbyname";
384#endif
385                m_data = m_resolv_host;
386                Send( msg );
387                return;
388        }
389#ifdef ENABLE_IPV6
390        if (m_resolve_ipv6)
391        {
392                std::string tmp;
393                Utility::l2ip(m_resolv_address6, tmp);
394                m_query = "gethostbyaddr";
395                m_data = tmp;
396                std::string msg = "gethostbyaddr " + tmp + "\n";
397                Send( msg );
398        }
399#endif
400        std::string tmp;
401        Utility::l2ip(m_resolv_address, tmp);
402        m_query = "gethostbyaddr";
403        m_data = tmp;
404        std::string msg = "gethostbyaddr " + tmp + "\n";
405        Send( msg );
406}
407
408
409void ResolvSocket::OnDelete()
410{
411        if (m_parent)
412        {
413                if (Handler().Resolving(m_parent) || Handler().Valid(m_parent))
414                {
415                        m_parent -> OnResolveFailed(m_resolv_id);
416                }
417                // update cache
418                if (!m_cached)
419                {
420                        Lock lock(m_cache_mutex);
421                        std::string value;
422DEB(fprintf(stderr, " *** Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
423                        m_cache[m_query][m_data] = value;
424                        m_cache_to[m_query][m_data] = time(NULL);
425                }
426                m_parent = NULL;
427        }
428}
429
430
431#ifdef SOCKETS_NAMESPACE
432}
433#endif
434
435#endif // ENABLE_RESOLVER
436
Note: See TracBrowser for help on using the browser.