gresolver_unix.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 Graeme Walker <graeme_walker@users.sourceforge.net>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gresolver_unix.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gresolver.h"
23 #include "glinebuffer.h"
24 #include "gsimpleclient.h"
25 #include "gsocketprotocol.h"
26 #include "gresolverinfo.h"
27 #include "gexception.h"
28 #include "gsocket.h"
29 #include "gevent.h"
30 #include "gmemory.h"
31 #include "gstr.h"
32 #include "gdebug.h"
33 #include "glog.h"
34 
35 namespace
36 {
37  const unsigned int c_port = 208U ;
38 }
39 
50 {
51 public:
52  ResolverImp( EventHandler & event_handler , Resolver & resolver , unsigned int port ) ;
53  // Constructor.
54 
55  virtual ~ResolverImp() ;
56  // Destructor.
57 
58  bool resolveReq( std::string host_part, std::string service_part , bool udp ) ;
59  // Issues a resolve request for the given host and service names.
60 
61  bool busy() const ;
62  // Returns true if resolving is currently in progress.
63 
64 protected:
65  virtual void onConnect() ;
66  virtual void onSendComplete() ;
67  virtual void onData( const char * , std::string::size_type ) ;
68  virtual void onSecure( const std::string & ) ;
69  virtual void onException( std::exception & ) ;
70 
71 private:
72  void operator=( const ResolverImp & ) ; // not implemented
73  ResolverImp( const ResolverImp & ) ; // not implemented
74  static ResolverInfo resolverInfo( unsigned int ) ;
75 
76 private:
77  EventHandler & m_event_handler ;
78  Resolver & m_outer ;
79  LineBuffer m_line_buffer ;
80  std::string m_request ;
81 } ;
82 
83 // ===
84 
85 GNet::ResolverImp::ResolverImp( EventHandler & event_handler , Resolver & resolver , unsigned int port ) :
86  SimpleClient(resolverInfo(port)) ,
87  m_event_handler(event_handler) ,
88  m_outer(resolver)
89 {
90 }
91 
93 {
94 }
95 
97 {
98  ResolverInfo info( "localhost" , "0" ) ;
99  info.update( Address::localhost(port) , "localhost" ) ;
100  return info ;
101 }
102 
103 bool GNet::ResolverImp::resolveReq( std::string host_part, std::string service_part , bool udp )
104 {
105  if( ! m_request.empty() )
106  return false ; // still busy
107  m_request = host_part + ":" + service_part + ":" + ( udp ? "udp" : "tcp" ) + "\n" ;
108 
109  if( connected() )
110  send( m_request ) ;
111  else
112  connect() ;
113 
114  return true ;
115 }
116 
118 {
119  if( ! m_request.empty() )
120  send( m_request ) ;
121 }
122 
124 {
125 }
126 
127 void GNet::ResolverImp::onSecure( const std::string & )
128 {
129 }
130 
132 {
133  m_line_buffer.add( p , n ) ;
134  while( m_line_buffer.more() )
135  {
136  m_request.erase() ;
137 
138  std::string result = m_line_buffer.line() ;
139  G_DEBUG( "GNet::ResolverImp::readEvent: \"" << result << "\"" ) ;
140  G::Str::trim( result , " \n\r" ) ;
141  std::string::size_type pos = result.find( ' ' ) ;
142  std::string head = pos == std::string::npos ? result : result.substr(0U,pos) ;
143  std::string tail = pos == std::string::npos ? std::string() : result.substr(pos+1U) ;
144  if( Address::validString(head) )
145  {
146  G::Str::trim( tail , " \n" ) ;
147  m_outer.resolveCon( true , Address(head) , tail ) ;
148  }
149  else
150  {
151  std::string reason = result ;
152  reason = G::Str::isPrintableAscii( reason ) ? reason : std::string("dns error") ;
153  m_outer.resolveCon( false , Address::invalidAddress() , reason ) ;
154  }
155  }
156 }
157 
158 void GNet::ResolverImp::onException( std::exception & e )
159 {
160  if( busy() )
161  {
162  m_request.erase() ;
163  m_outer.resolveCon( false , Address::invalidAddress() , e.what() ) ;
164  }
165  else
166  {
167  m_event_handler.onException( e ) ;
168  }
169 }
170 
172 {
173  return ! m_request.empty() ;
174 }
175 
176 // ===
177 
179  m_imp(new ResolverImp(event_handler,*this,c_port))
180 {
181 }
182 
184 {
185  delete m_imp ;
186 }
187 
188 bool GNet::Resolver::resolveReq( std::string name , bool udp )
189 {
190  std::string host_part ;
191  std::string service_part ;
192  if( ! parse(name,host_part,service_part) )
193  return false ;
194 
195  return m_imp->resolveReq( host_part , service_part , udp ) ;
196 }
197 
198 bool GNet::Resolver::resolveReq( std::string host_part, std::string service_part , bool udp )
199 {
200  if( m_imp == NULL )
201  return false ;
202 
203  if( host_part.length() == 0 )
204  host_part = "0.0.0.0" ;
205 
206  if( service_part.length() == 0 )
207  service_part = "0" ;
208 
209  return m_imp->resolveReq( host_part , service_part , udp ) ;
210 }
211 
212 void GNet::Resolver::resolveCon( bool , const Address & , std::string )
213 {
214  // no-op
215 }
216 
218 {
219  return m_imp->busy() ;
220 }
221 
virtual ~Resolver()
Virtual destructor.
virtual void onSecure(const std::string &)
Called once the secure socket protocol has been successfully negotiated.
static Address localhost(unsigned int port=0U)
Returns a localhost ("loopback") address.
A class for making an outgoing connection to a remote server, with support for socket-level protocols...
Definition: gsimpleclient.h:81
virtual void onConnect()
Called once connected.
A class for asynchronous TCP name-to-address resolution.
Definition: gresolver.h:45
The Address class encapsulates an IP transport address.
Definition: gaddress.h:48
bool resolveReq(std::string host_part, std::string service_part, bool udp)
A class that holds a host/service name pair and optionally the results of a name-to-address lookup...
Definition: gresolverinfo.h:48
std::string::size_type size_type
A std::size_t type.
Definition: md5.h:43
static Address invalidAddress()
Returns an invalid address.
virtual void resolveCon(bool success, const Address &address, std::string fqdn_or_failure_reason)
Called when the resolution process is complete.
static void trim(std::string &s, const std::string &ws)
Trims both ends of s, taking off any of the 'ws' characters.
Definition: gstr.cpp:133
virtual void onSendComplete()
Called when all residual data from send() has been sent.
A base class for classes that handle asynchronous socket events.
Definition: geventhandler.h:54
virtual void onData(const char *, std::string::size_type)
Called when data is read from the socket.
#define G_DEBUG(expr)
Definition: glog.h:95
bool busy() const
static bool isPrintableAscii(const std::string &s)
Returns true if every character is a 7-bit, non-control character (ie.
Definition: gstr.cpp:167
static bool validString(const std::string &display_string, std::string *reason=NULL)
Returns true if the display string is valid.
A class which does line buffering.
Definition: glinebuffer.h:52
bool busy() const
Returns true if there is a pending resolve request.
ResolverInfo resolverInfo() const
Returns a ResolverInfo structure containing the result of host() and service() name lookup if availab...
ResolverImp(EventHandler &event_handler, Resolver &resolver, unsigned int port)
virtual void onException(std::exception &)
Called when an exception is thrown out of readEvent(), writeEvent() or exceptionEvent().
bool resolveReq(std::string name, bool udp=false)
Initiates a name-to-address resolution.
Resolver(EventHandler &)
Constructor taking an event handler reference.
A pimple-pattern implementation class for GNet::Resolver.