E-MailRelay
glocation.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2021 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/// \file glocation.cpp
19///
20
21#include "gdef.h"
22#include "gstr.h"
23#include "glocation.h"
24#include "gresolver.h"
25#include "gassert.h"
26
27GNet::Location::Location( const std::string & spec , int family ) :
28 m_host(head(sockless(spec))) ,
29 m_service(tail(sockless(spec))) ,
30 m_address_valid(false) ,
31 m_address(Address::defaultAddress()) ,
32 m_family(family) ,
33 m_update_time(0U) ,
34 m_using_socks(false)
35{
36 m_using_socks = socksified( spec , m_socks_far_host , m_socks_far_port ) ;
37 if( m_host.empty() )
38 throw InvalidFormat( spec ) ;
39 G_DEBUG( "GNet::Location::ctor: unresolved location [" << displayString() << "]" << (m_using_socks?" (using socks)":"") ) ;
40}
41
42GNet::Location::Location( const std::string & spec , int family , int ) : // nosocks() overload
43 m_host(head(spec)) ,
44 m_service(tail(spec)) ,
45 m_address_valid(false) ,
46 m_address(Address::defaultAddress()) ,
47 m_family(family) ,
48 m_update_time(0U) ,
49 m_using_socks(false)
50{
51 G_DEBUG( "GNet::Location::ctor: unresolved location [" << displayString() << "]" ) ;
52}
53
54GNet::Location::Location( const std::string & socks_server , const std::string & far_server , int family ) : // socks() overload
55 m_host(head(socks_server)) ,
56 m_service(tail(socks_server)) ,
57 m_address_valid(false) ,
58 m_address(Address::defaultAddress()) ,
59 m_family(family) ,
60 m_update_time(0U) ,
61 m_using_socks(true) ,
62 m_socks_far_host(head(far_server)) ,
63 m_socks_far_port(tail(far_server))
64{
65 if( m_socks_far_host.empty() || m_socks_far_port.empty() )
66 throw InvalidFormat() ;
67 if( !G::Str::isUInt(m_socks_far_port) )
68 throw InvalidFormat( "invalid port number: [" + m_socks_far_port + "]" ) ;
69 G_DEBUG( "GNet::Location::ctor: unresolved location [" << displayString() << "]" << " (using socks)" ) ;
70}
71
72GNet::Location GNet::Location::nosocks( const std::string & spec , int family )
73{
74 return { spec , family , 1 } ;
75}
76
77GNet::Location GNet::Location::socks( const std::string & socks_server , const std::string & far_server )
78{
79 return { socks_server , far_server , AF_UNSPEC } ;
80}
81
82std::string GNet::Location::sockless( const std::string & s )
83{
84 // "far-host:far-port@sockserver-host:sockserver-port"
85 return G::Str::tail( s , s.find('@') , s ) ;
86}
87
88bool GNet::Location::socksified( const std::string & s , std::string & far_host_out , std::string & far_port_out )
89{
90 std::string::size_type pos = s.find('@') ;
91 if( pos != std::string::npos )
92 {
93 std::string ss = G::Str::head( s , pos ) ;
94 far_host_out = G::Str::head( ss , ss.rfind(':') ) ;
95 far_port_out = G::Str::tail( ss , ss.rfind(':') ) ;
96 G::Str::toUInt( far_port_out ) ; // throw if not a number
97 }
98 return pos != std::string::npos ;
99}
100
101std::string GNet::Location::head( const std::string & s )
102{
103 std::size_t pos = s.rfind( ':' ) ;
104 std::string h = ( pos == std::string::npos && !s.empty() && s[0] == '/' ) ? s : G::Str::head( s , pos ) ;
105 if( h.size() > 1U && h.at(0U) == '[' && h.at(h.size()-1U) == ']' )
106 h = h.substr( 1U , h.size()-2U ) ;
107 return h ;
108}
109
110std::string GNet::Location::tail( const std::string & s )
111{
112 return G::Str::tail( s , s.rfind(':') ) ;
113}
114
115std::string GNet::Location::host() const
116{
117 return m_host ;
118}
119
120std::string GNet::Location::service() const
121{
122 return m_service ;
123}
124
126{
127 return m_family ;
128}
129
131{
132 std::string reason ;
133 std::string address_string = G::Str::join( ":" , m_host , m_service ) ;
134 if( !resolved() && Address::validString(address_string,&reason) )
135 {
136 Address address = Address::parse( address_string ) ;
137 update( address , std::string() ) ;
138 }
139 return resolved() ;
140}
141
143{
144 return m_address_valid ;
145}
146
148{
149 return m_address ;
150}
151
152void GNet::Location::update( const Address & address , const std::string & name )
153{
154 if( !update(address,name,std::nothrow) )
155 throw InvalidFamily() ;
156}
157
158bool GNet::Location::update( const Address & address , const std::string & name , std::nothrow_t )
159{
160 bool valid_family =
161 address.family() == Address::Family::ipv4 ||
162 address.family() == Address::Family::ipv6 ||
163 address.family() == Address::Family::local ;
164
165 if( !valid_family || ( m_family != AF_UNSPEC && address.af() != m_family ) )
166 return false ;
167
168 m_address = address ;
169 m_family = address.af() ; // not enum
170 m_address_valid = true ;
171 m_canonical_name = name ;
172 m_update_time = G::SystemTime::now() ;
173 G_DEBUG( "GNet::Location::ctor: resolved location [" << displayString() << "]" ) ;
174 return true ;
175}
176
177std::string GNet::Location::name() const
178{
179 return m_canonical_name ;
180}
181
183{
184 if( resolved() )
185 {
186 return address().displayString() ;
187 }
188 else if( m_host.find('/') == 0U )
189 {
190 return m_host ;
191 }
192 else
193 {
194 const char * ipvx = m_family == AF_UNSPEC ? "ip" : ( m_family == AF_INET ? "ipv4" : "ipv6" ) ;
195 return m_host + "/" + m_service + "/" + ipvx ;
196 }
197}
198
200{
201 return m_update_time ;
202}
203
205{
206 return m_using_socks ;
207}
208
210{
211 G_ASSERT( m_socks_far_port.empty() || G::Str::isUInt(m_socks_far_port) ) ;
212 return m_socks_far_port.empty() ? 0U : G::Str::toUInt(m_socks_far_port) ;
213}
214
216{
217 return m_socks_far_host ;
218}
219
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:53
Family family() const
Returns the address family enumeration.
Definition: gaddress.cpp:491
int af() const
Returns the address family number such as AF_INET or AFINET6.
Definition: gaddress.cpp:500
static Address parse(const std::string &display_string)
Factory function for any address family.
Definition: gaddress.cpp:217
static bool validString(const std::string &display_string, std::string *reason=nullptr)
Returns true if the transport-address display string is valid.
Definition: gaddress.cpp:402
A class that represents the remote target for out-going client connections.
Definition: glocation.h:71
int family() const
Returns the preferred name resolution address family as passed to the constructor.
Definition: glocation.cpp:125
bool resolved() const
Returns true after update() has been called or resolveTrivially() succeeded.
Definition: glocation.cpp:142
bool resolveTrivially()
If host() and service() are already in address format then do a trivial update() so that the location...
Definition: glocation.cpp:130
std::string name() const
Returns the remote canonical name.
Definition: glocation.cpp:177
std::string displayString() const
Returns a string representation for logging and debug.
Definition: glocation.cpp:182
std::string socksFarHost() const
Returns the port for the socks far server.
Definition: glocation.cpp:215
G::SystemTime updateTime() const
Returns the time of the last update() or zero if never update()d.
Definition: glocation.cpp:199
bool socks() const
Returns true if a socks location.
Definition: glocation.cpp:204
void update(const Address &address, const std::string &canonical_name)
Updates the address and canonical name, typically after doing a name lookup on host() and service().
Definition: glocation.cpp:152
std::string service() const
Returns the remote service name derived from the constructor parameter.
Definition: glocation.cpp:120
unsigned int socksFarPort() const
Returns the port number for the socks far server.
Definition: glocation.cpp:209
Address address() const
Returns the remote address.
Definition: glocation.cpp:147
std::string host() const
Returns the remote host name derived from the constructor parameter.
Definition: glocation.cpp:115
Location(const std::string &spec, int family=AF_UNSPEC)
Constructor taking a formatted "host:service" string.
Definition: glocation.cpp:27
static Location nosocks(const std::string &spec, int family=AF_UNSPEC)
Factory function for a remote location but not allowing the extended syntax for socks.
Definition: glocation.cpp:72
static std::string join(const std::string &sep, const StringArray &strings)
Concatenates an array of strings with separators.
Definition: gstr.cpp:1195
static std::string tail(const std::string &in, std::size_t pos, const std::string &default_=std::string())
Returns the last part of the string after the given position.
Definition: gstr.cpp:1287
static unsigned int toUInt(const std::string &s)
Converts string 's' to an unsigned int.
Definition: gstr.cpp:604
static bool isUInt(const std::string &s)
Returns true if the string can be converted into an unsigned integer without throwing an exception.
Definition: gstr.cpp:444
static std::string head(const std::string &in, std::size_t pos, const std::string &default_=std::string())
Returns the first part of the string up to just before the given position.
Definition: gstr.cpp:1273
Represents a unix-epoch time with microsecond resolution.
Definition: gdatetime.h:125
static SystemTime now()
Factory function for the current time.
Definition: gdatetime.cpp:260