Logo
~Sockets~
~Examples~
~Contact~


ResolvSocket.cpp

Go to the documentation of this file.
00001 
00005 /*
00006 Copyright (C) 2004-2007  Anders Hedstrom
00007 
00008 This library is made available under the terms of the GNU GPL.
00009 
00010 If you would like to use this library in a closed-source application,
00011 a separate license agreement is available. For information about
00012 the closed-source license agreement for the C++ sockets library,
00013 please visit http://www.alhem.net/Sockets/license.html and/or
00014 email license@alhem.net.
00015 
00016 This program is free software; you can redistribute it and/or
00017 modify it under the terms of the GNU General Public License
00018 as published by the Free Software Foundation; either version 2
00019 of the License, or (at your option) any later version.
00020 
00021 This program is distributed in the hope that it will be useful,
00022 but WITHOUT ANY WARRANTY; without even the implied warranty of
00023 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024 GNU General Public License for more details.
00025 
00026 You should have received a copy of the GNU General Public License
00027 along with this program; if not, write to the Free Software
00028 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00029 */
00030 #ifdef _WIN32
00031 #pragma warning(disable:4786)
00032 #pragma warning(disable:4503)
00033 #else
00034 #include <netdb.h>
00035 #endif
00036 #include "ResolvSocket.h"
00037 #ifdef ENABLE_RESOLVER
00038 #include "Utility.h"
00039 #include "Parse.h"
00040 #include "ISocketHandler.h"
00041 #include "Lock.h"
00042 
00043 #ifdef SOCKETS_NAMESPACE
00044 namespace SOCKETS_NAMESPACE {
00045 #endif
00046 
00047 #ifdef _DEBUG
00048 #define DEB(x) x
00049 #else
00050 #define DEB(x)
00051 #endif
00052 
00053 
00054 // static
00055 ResolvSocket::cache_t ResolvSocket::m_cache;
00056 ResolvSocket::timeout_t ResolvSocket::m_cache_to;
00057 Mutex ResolvSocket::m_cache_mutex;
00058 
00059 
00060 ResolvSocket::ResolvSocket(ISocketHandler& h)
00061 :TcpSocket(h)
00062 ,m_bServer(false)
00063 ,m_parent(NULL)
00064 #ifdef ENABLE_IPV6
00065 ,m_resolve_ipv6(false)
00066 #endif
00067 ,m_cached(false)
00068 {
00069         SetLineProtocol();
00070 }
00071 
00072 
00073 ResolvSocket::ResolvSocket(ISocketHandler& h, Socket *parent, const std::string& host, port_t port, bool ipv6)
00074 :TcpSocket(h)
00075 ,m_bServer(false)
00076 ,m_parent(parent)
00077 ,m_resolv_host(host)
00078 ,m_resolv_port(port)
00079 #ifdef ENABLE_IPV6
00080 ,m_resolve_ipv6(ipv6)
00081 #endif
00082 ,m_cached(false)
00083 {
00084         SetLineProtocol();
00085 }
00086 
00087 
00088 ResolvSocket::ResolvSocket(ISocketHandler& h, Socket *parent, ipaddr_t a)
00089 :TcpSocket(h)
00090 ,m_bServer(false)
00091 ,m_parent(parent)
00092 ,m_resolv_port(0)
00093 ,m_resolv_address(a)
00094 #ifdef ENABLE_IPV6
00095 ,m_resolve_ipv6(false)
00096 #endif
00097 ,m_cached(false)
00098 {
00099         SetLineProtocol();
00100 }
00101 
00102 
00103 #ifdef ENABLE_IPV6
00104 ResolvSocket::ResolvSocket(ISocketHandler& h, Socket *parent, in6_addr& a)
00105 :TcpSocket(h)
00106 ,m_bServer(false)
00107 ,m_parent(parent)
00108 ,m_resolv_port(0)
00109 ,m_resolve_ipv6(true)
00110 ,m_resolv_address6(a)
00111 ,m_cached(false)
00112 {
00113         SetLineProtocol();
00114 }
00115 #endif
00116 
00117 
00118 ResolvSocket::~ResolvSocket()
00119 {
00120 }
00121 
00122 
00123 void ResolvSocket::OnLine(const std::string& line)
00124 {
00125         Parse pa(line, ":");
00126         if (m_bServer)
00127         {
00128                 m_query = pa.getword();
00129                 m_data = pa.getrest();
00130 DEB(            fprintf(stderr, "ResolvSocket server; query=%s, data=%s\n", m_query.c_str(), m_data.c_str());)
00131                 // %! check cache
00132                 {
00133                         Lock lock(m_cache_mutex);
00134                         if (m_cache[m_query].find(m_data) != m_cache[m_query].end())
00135                         {
00136                                 if (time(NULL) - m_cache_to[m_query][m_data] < 3600) // ttl
00137                                 {
00138                                         std::string result = m_cache[m_query][m_data];
00139 DEB(printf("Returning cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), result.c_str());)
00140                                         Send("Cached\n");
00141                                         if (!result.size()) /* failed */
00142                                         {
00143                                                 Send("Failed\n\n");
00144                                                 SetCloseAndDelete();
00145                                                 return;
00146                                         }
00147                                         else
00148                                         if (m_query == "gethostbyname")
00149                                         {
00150                                                 Send("A: " + result + "\n\n");
00151                                                 SetCloseAndDelete();
00152                                                 return;
00153                                         }
00154                                         else
00155 #ifdef ENABLE_IPV6
00156 #ifdef IPPROTO_IPV6
00157                                         if (m_query == "gethostbyname2")
00158                                         {
00159                                                 Send("AAAA: " + result + "\n\n");
00160                                                 SetCloseAndDelete();
00161                                                 return;
00162                                         }
00163                                         else
00164 #endif
00165 #endif
00166                                         if (m_query == "gethostbyaddr")
00167                                         {
00168                                                 Send("Name: " + result + "\n\n");
00169                                                 SetCloseAndDelete();
00170                                                 return;
00171                                         }
00172                                 }
00173                         }
00174                 }
00175                 if (!Detach()) // detach failed?
00176                 {
00177                         SetCloseAndDelete();
00178                 }
00179                 return;
00180         }
00181         std::string key = pa.getword();
00182         std::string value = pa.getrest();
00183 
00184         if (key == "Cached")
00185         {
00186                 m_cached = true;
00187         }
00188         else
00189         if (key == "Failed" && m_parent)
00190         {
00191 DEB(            fprintf(stderr, "************ Resolve failed\n");)
00192                 if (Handler().Valid(m_parent))
00193                 {
00194                         m_parent -> OnResolveFailed(m_resolv_id);
00195                 }
00196                 // update cache
00197                 if (!m_cached)
00198                 {
00199                         Lock lock(m_cache_mutex);
00200 DEB(printf("Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
00201                         m_cache[m_query][m_data] = value;
00202                         m_cache_to[m_query][m_data] = time(NULL);
00203                 }
00204                 m_parent = NULL;
00205         }
00206         else
00207         if (key == "Name" && !m_resolv_host.size() && m_parent)
00208         {
00209                 if (Handler().Valid(m_parent))
00210                 {
00211                         m_parent -> OnReverseResolved(m_resolv_id, value);
00212                 }
00213                 // update cache
00214                 if (!m_cached)
00215                 {
00216                         Lock lock(m_cache_mutex);
00217 DEB(printf("Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
00218                         m_cache[m_query][m_data] = value;
00219                         m_cache_to[m_query][m_data] = time(NULL);
00220                 }
00221                 m_parent = NULL;
00222         }
00223         else
00224         if (key == "A" && m_parent)
00225         {
00226                 ipaddr_t l;
00227                 Utility::u2ip(value, l); // ip2ipaddr_t
00228                 if (Handler().Valid(m_parent))
00229                 {
00230                         m_parent -> OnResolved(m_resolv_id, l, m_resolv_port);
00231                 }
00232                 // update cache
00233                 if (!m_cached)
00234                 {
00235                         Lock lock(m_cache_mutex);
00236 DEB(printf("Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
00237                         m_cache[m_query][m_data] = value;
00238                         m_cache_to[m_query][m_data] = time(NULL);
00239                 }
00240                 m_parent = NULL; // always use first ip in case there are several
00241         }
00242 #ifdef ENABLE_IPV6
00243 #ifdef IPPROTO_IPV6
00244         else
00245         if (key == "AAAA" && m_parent)
00246         {
00247                 in6_addr a;
00248                 Utility::u2ip(value, a);
00249                 if (Handler().Valid(m_parent))
00250                 {
00251                         m_parent -> OnResolved(m_resolv_id, a, m_resolv_port);
00252                 }
00253                 // update cache
00254                 if (!m_cached)
00255                 {
00256                         Lock lock(m_cache_mutex);
00257 DEB(printf("Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
00258                         m_cache[m_query][m_data] = value;
00259                         m_cache_to[m_query][m_data] = time(NULL);
00260                 }
00261                 m_parent = NULL;
00262         }
00263 #endif
00264 #endif
00265 }
00266 
00267 
00268 void ResolvSocket::OnDetached()
00269 {
00270 DEB(    fprintf(stderr, "ResolvSocket::OnDetached(); query=%s, data=%s\n", m_query.c_str(), m_data.c_str());)
00271         if (m_query == "gethostbyname")
00272         {
00273                 struct sockaddr_in sa;
00274                 if (Utility::u2ip(m_data, sa))
00275                 {
00276                         std::string ip;
00277                         Utility::l2ip(sa.sin_addr, ip);
00278                         Send("A: " + ip + "\n");
00279                 }
00280                 else
00281                 {
00282                         Send("Failed\n");
00283                 }
00284                 Send("\n");
00285         }
00286         else
00287 #ifdef ENABLE_IPV6
00288 #ifdef IPPROTO_IPV6
00289         if (m_query == "gethostbyname2")
00290         {
00291                 struct sockaddr_in6 sa;
00292                 if (Utility::u2ip(m_data, sa))
00293                 {
00294                         std::string ip;
00295                         Utility::l2ip(sa.sin6_addr, ip);
00296                         Send("AAAA: " + ip + "\n");
00297                 }
00298                 else
00299                 {
00300                         Send("Failed\n");
00301                 }
00302                 Send("\n");
00303         }
00304         else
00305 #endif
00306 #endif
00307         if (m_query == "gethostbyaddr")
00308         {
00309                 if (Utility::isipv4( m_data ))
00310                 {
00311                         struct sockaddr_in sa;
00312                         if (!Utility::u2ip(m_data, sa, AI_NUMERICHOST))
00313                         {
00314                                 Send("Failed: convert to sockaddr_in failed\n");
00315                         }
00316                         else
00317                         {
00318                                 std::string name;
00319                                 if (!Utility::reverse( (struct sockaddr *)&sa, sizeof(sa), name))
00320                                 {
00321                                         Send("Failed: ipv4 reverse lookup of " + m_data + "\n");
00322                                 }
00323                                 else
00324                                 {
00325                                         Send("Name: " + name + "\n");
00326                                 }
00327                         }
00328                 }
00329                 else
00330 #ifdef ENABLE_IPV6
00331 #ifdef IPPROTO_IPV6
00332                 if (Utility::isipv6( m_data ))
00333                 {
00334                         struct sockaddr_in6 sa;
00335                         if (!Utility::u2ip(m_data, sa, AI_NUMERICHOST))
00336                         {
00337                                 Send("Failed: convert to sockaddr_in6 failed\n");
00338                         }
00339                         else
00340                         {
00341                                 std::string name;
00342                                 if (!Utility::reverse( (struct sockaddr *)&sa, sizeof(sa), name))
00343                                 {
00344                                         Send("Failed: ipv6 reverse lookup of " + m_data + "\n");
00345                                 }
00346                                 else
00347                                 {
00348                                         Send("Name: " + name + "\n");
00349                                 }
00350                         }
00351                 }
00352                 else
00353 #endif
00354 #endif
00355                 {
00356                         Send("Failed: malformed address\n");
00357                 }
00358                 Send("\n");
00359         }
00360         else
00361         {
00362                 std::string msg = "Unknown query type: " + m_query;
00363                 Handler().LogError(this, "OnDetached", 0, msg);
00364                 Send("Unknown\n\n");
00365         }
00366         SetCloseAndDelete();
00367 }
00368 
00369 
00370 void ResolvSocket::OnConnect()
00371 {
00372         if (m_resolv_host.size())
00373         {
00374 #ifdef ENABLE_IPV6
00375                 std::string msg = (m_resolve_ipv6 ? "gethostbyname2 " : "gethostbyname ") + m_resolv_host + "\n";
00376                 m_query = m_resolve_ipv6 ? "gethostbyname2" : "gethostbyname";
00377 #else
00378                 std::string msg = "gethostbyname " + m_resolv_host + "\n";
00379                 m_query = "gethostbyname";
00380 #endif
00381                 m_data = m_resolv_host;
00382                 Send( msg );
00383                 return;
00384         }
00385 #ifdef ENABLE_IPV6
00386         if (m_resolve_ipv6)
00387         {
00388                 std::string tmp;
00389                 Utility::l2ip(m_resolv_address6, tmp);
00390                 m_query = "gethostbyaddr";
00391                 m_data = tmp;
00392                 std::string msg = "gethostbyaddr " + tmp + "\n";
00393                 Send( msg );
00394         }
00395 #endif
00396         std::string tmp;
00397         Utility::l2ip(m_resolv_address, tmp);
00398         m_query = "gethostbyaddr";
00399         m_data = tmp;
00400         std::string msg = "gethostbyaddr " + tmp + "\n";
00401         Send( msg );
00402 }
00403 
00404 
00405 void ResolvSocket::OnDelete()
00406 {
00407         if (m_parent)
00408         {
00409                 if (Handler().Valid(m_parent))
00410                 {
00411                         m_parent -> OnResolveFailed(m_resolv_id);
00412                 }
00413                 // update cache
00414                 if (!m_cached)
00415                 {
00416                         Lock lock(m_cache_mutex);
00417                         std::string value;
00418 DEB(printf("Update cache for [%s][%s] = '%s'\n", m_query.c_str(), m_data.c_str(), value.c_str());)
00419                         m_cache[m_query][m_data] = value;
00420                         m_cache_to[m_query][m_data] = time(NULL);
00421                 }
00422                 m_parent = NULL;
00423         }
00424 }
00425 
00426 
00427 #ifdef SOCKETS_NAMESPACE
00428 }
00429 #endif
00430 
00431 #endif // ENABLE_RESOLVER
Page, code, and content Copyright (C) 2007 by Anders Hedström
Generated for C++ Sockets by  doxygen 1.4.4