E-MailRelay
glocation.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 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#include "glog.h"
27
28GNet::Location::Location( const std::string & spec , int family ) :
29 m_host(head(sockless(spec))) ,
30 m_service(tail(sockless(spec))) ,
31 m_address_valid(false) ,
32 m_address(Address::defaultAddress()) ,
33 m_family(family) ,
34 m_update_time(0U) ,
35 m_using_socks(false)
36{
37 m_using_socks = socksified( spec , m_socks_far_host , m_socks_far_port ) ;
38 if( m_host.empty() )
39 throw InvalidFormat( spec ) ; // eg. ":25"
40 G_DEBUG( "GNet::Location::ctor: unresolved location [" << displayString() << "]" << (m_using_socks?" (using socks)":"") ) ;
41}
42
43GNet::Location::Location( const std::string & spec , int family , int ) : // nosocks() overload
44 m_host(head(spec)) ,
45 m_service(tail(spec)) ,
46 m_address_valid(false) ,
47 m_address(Address::defaultAddress()) ,
48 m_family(family) ,
49 m_update_time(0U) ,
50 m_using_socks(false)
51{
52 G_DEBUG( "GNet::Location::ctor: unresolved location [" << displayString() << "]" ) ;
53 if( m_host.empty() )
54 throw InvalidFormat( spec ) ;
55}
56
57GNet::Location::Location( const std::string & socks_server , const std::string & far_server , int family ) : // socks() overload
58 m_host(head(socks_server)) ,
59 m_service(tail(socks_server)) ,
60 m_address_valid(false) ,
61 m_address(Address::defaultAddress()) ,
62 m_family(family) ,
63 m_update_time(0U) ,
64 m_using_socks(true) ,
65 m_socks_far_host(head(far_server)) ,
66 m_socks_far_port(tail(far_server))
67{
68 if( m_socks_far_host.empty() || m_socks_far_port.empty() )
69 throw InvalidFormat() ;
70 if( !G::Str::isUInt(m_socks_far_port) )
71 throw InvalidFormat( "invalid port number: [" + m_socks_far_port + "]" ) ;
72 if( m_host.empty() )
73 throw InvalidFormat( socks_server ) ;
74 G_DEBUG( "GNet::Location::ctor: unresolved location [" << displayString() << "]" << " (using socks)" ) ;
75}
76
77GNet::Location GNet::Location::nosocks( const std::string & spec , int family )
78{
79 return { spec , family , 1 } ;
80}
81
82#ifndef G_LIB_SMALL
83GNet::Location GNet::Location::socks( const std::string & socks_server , const std::string & far_server )
84{
85 return { socks_server , far_server , AF_UNSPEC } ;
86}
87#endif
88
89std::string GNet::Location::sockless( const std::string & s )
90{
91 // "far-host:far-port@sockserver-host:sockserver-port"
92 return G::Str::tail( s , s.find('@') , s ) ;
93}
94
95bool GNet::Location::socksified( const std::string & s , std::string & far_host_out , std::string & far_port_out )
96{
97 std::string::size_type pos = s.find('@') ;
98 if( pos != std::string::npos )
99 {
100 std::string ss = G::Str::head( s , pos ) ;
101 far_host_out = G::Str::head( ss , ss.rfind(':') ) ;
102 far_port_out = G::Str::tail( ss , ss.rfind(':') ) ;
103 G::Str::toUInt( far_port_out ) ; // throw if not a number
104 }
105 return pos != std::string::npos ;
106}
107
108std::string GNet::Location::head( const std::string & s )
109{
110 std::size_t pos = s.rfind( ':' ) ;
111 std::string h = ( pos == std::string::npos && !s.empty() && s[0] == '/' ) ? s : G::Str::head( s , pos ) ; // eg. "/tmp/socket"
112 if( h.size() > 1U && h.at(0U) == '[' && h.at(h.size()-1U) == ']' ) // eg. "[::1]:25"
113 h = h.substr( 1U , h.size()-2U ) ;
114 return h ;
115}
116
117std::string GNet::Location::tail( const std::string & s )
118{
119 return G::Str::tail( s , s.rfind(':') ) ;
120}
121
122std::string GNet::Location::host() const
123{
124 return m_host ;
125}
126
127std::string GNet::Location::service() const
128{
129 return m_service ;
130}
131
133{
134 return m_family ;
135}
136
138{
139 std::string reason ;
140 std::string address_string = G::Str::join( ":" , m_host , m_service ) ;
141 if( !resolved() && Address::validString(address_string,&reason) )
142 {
143 update( Address::parse(address_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 )
159{
160 if( !update(address,std::nothrow) )
161 throw InvalidFamily() ;
162}
163
164bool GNet::Location::update( const Address & address , 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_update_time = G::SystemTime::now() ;
178 G_DEBUG( "GNet::Location::ctor: resolved location [" << displayString() << "]" ) ;
179 return true ;
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
199#ifndef G_LIB_SMALL
201{
202 return m_update_time ;
203}
204#endif
205
207{
208 return m_using_socks ;
209}
210
212{
213 G_ASSERT( m_socks_far_port.empty() || G::Str::isUInt(m_socks_far_port) ) ;
214 return m_socks_far_port.empty() ? 0U : G::Str::toUInt(m_socks_far_port) ;
215}
216
218{
219 return m_socks_far_host ;
220}
221
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:63
int af() const noexcept
Returns the address family number such as AF_INET or AFINET6.
Definition: gaddress.cpp:482
static bool validString(std::string_view display_string, std::string *reason=nullptr)
Returns true if the transport-address display string is valid.
Definition: gaddress.cpp:383
static Address parse(std::string_view display_string)
Factory function for any address family.
Definition: gaddress.cpp:178
Family family() const noexcept
Returns the address family enumeration.
Definition: gaddress.cpp:474
A class that represents the remote target for out-going client connections.
Definition: glocation.h:70
int family() const
Returns the preferred name resolution address family as passed to the constructor.
Definition: glocation.cpp:132
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:137
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:217
G::SystemTime updateTime() const
Returns the time of the last update() or zero if never update()d.
Definition: glocation.cpp:200
bool socks() const
Returns true if a socks location.
Definition: glocation.cpp:206
std::string service() const
Returns the remote service name derived from the constructor parameter.
Definition: glocation.cpp:127
unsigned int socksFarPort() const
Returns the port number for the socks far server.
Definition: glocation.cpp:211
void update(const Address &address)
Updates the address, typically after doing a name lookup on host() and service().
Definition: glocation.cpp:158
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:122
Location(const std::string &spec, int family=AF_UNSPEC)
Constructor taking a formatted "host:service" string.
Definition: glocation.cpp:28
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:77
static bool isUInt(std::string_view s) noexcept
Returns true if the string can be converted into an unsigned integer without throwing an exception.
Definition: gstr.cpp:446
static std::string join(std::string_view sep, const StringArray &strings)
Concatenates an array of strings with separators.
Definition: gstr.cpp:1221
static std::string tail(std::string_view in, std::size_t pos, std::string_view default_={})
Returns the last part of the string after the given position.
Definition: gstr.cpp:1322
static unsigned int toUInt(std::string_view s)
Converts string 's' to an unsigned int.
Definition: gstr.cpp:648
static std::string head(std::string_view in, std::size_t pos, std::string_view default_={})
Returns the first part of the string up to just before the given position.
Definition: gstr.cpp:1294
Represents a unix-epoch time with microsecond resolution.
Definition: gdatetime.h:140
static SystemTime now()
Factory function for the current time.
Definition: gdatetime.cpp:328