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