E-MailRelay

glisteners.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 glisteners.cpp
19///
20
21#include "gdef.h"
22#include "glisteners.h"
23#include "glog.h"
24#include "gassert.h"
25#include <algorithm>
26
27 GNet::Listeners::Listeners( const Interfaces & if_ , const G::StringArray & listener_list , unsigned int port )
28{
29 // listeners are file-descriptors, addresses or interface names (possibly decorated)
30 for( const auto & listener : listener_list )
31 {
32 int fd = G::is_windows() ? -1 : parseFd( listener ) ;
33 if( fd >= 0 )
34 {
35 m_fds.push_back( fd ) ;
36 }
37 else if( isAddress(listener,port) )
38 {
39 m_fixed.push_back( address(listener,port) ) ;
40 }
41 else
42 {
43 std::size_t n = if_.addresses( m_dynamic , basename(listener) , port , af(listener) ) ;
44 if( n == 0U && isBad(listener) )
45 m_bad = listener ;
46 (n?m_used:m_empties).push_back( listener ) ;
47 }
48 }
49 if( empty() )
50 addWildcards( port ) ;
51}
52
53 int GNet::Listeners::af( const std::string & s )
54{
55 if( G::Str::tailMatch(s,"-ipv6") )
56 return AF_INET6 ;
57 else if( G::Str::tailMatch(s,"-ipv4") )
58 return AF_INET ;
59 else
60 return AF_UNSPEC ;
61}
62
63std::string GNet::Listeners::basename( const std::string & s )
64{
65 return
66 G::Str::tailMatch(s,"-ipv6") || G::Str::tailMatch(s,"-ipv4") ?
67 s.substr( 0U , s.length()-5U ) :
68 s ;
69}
70
71 int GNet::Listeners::parseFd( const std::string & listener )
72{
73 if( listener.size() > 3U && listener.find("fd#") == 0U && G::Str::isUInt(listener.substr(3U)) )
74 {
75 int fd = G::Str::toInt( listener.substr(3U) ) ;
76 if( fd < 0 ) throw InvalidFd( listener ) ;
77 return fd ;
78 }
79 return -1 ;
80}
81
82 void GNet::Listeners::addWildcards( unsigned int port )
83{
84 if( StreamSocket::supports(Address::Family::ipv4) )
85 m_fixed.emplace_back( Address::Family::ipv4 , port ) ;
86
87 if( StreamSocket::supports(Address::Family::ipv6) )
88 m_fixed.emplace_back( Address::Family::ipv6 , port ) ;
89}
90
91 bool GNet::Listeners::isAddress( const std::string & s , unsigned int port )
92{
93 return Address::validStrings( s , G::Str::fromUInt(port) ) ;
94}
95
96 GNet::Address GNet::Listeners::address( const std::string & s , unsigned int port )
97{
98 return Address::parse( s , port ) ;
99}
100
101 bool GNet::Listeners::empty() const
102{
103 return m_fds.empty() && m_fixed.empty() && m_dynamic.empty() ;
104}
105
106 bool GNet::Listeners::defunct() const
107{
108 return empty() && !Interfaces::active() ;
109}
110
111 bool GNet::Listeners::idle() const
112{
113 return empty() && hasEmpties() && Interfaces::active() ;
114}
115
116 bool GNet::Listeners::noUpdates() const
117{
118 return !m_used.empty() && !Interfaces::active() ;
119}
120
121 bool GNet::Listeners::isBad( const std::string & s )
122{
123 // the input is not an address and not an interface-with-addresses so
124 // report it as bad if clearly not an interface-with-no-addresses --
125 // a slash is not normally allowed in an interface name, but allow "/dev/..."
126 // because of bsd
127 return s.empty() || ( s.find('/') != std::string::npos && s.find("/dev/") != 0U ) ;
128}
129
130 bool GNet::Listeners::hasBad() const
131{
132 return !m_bad.empty() ;
133}
134
135std::string GNet::Listeners::badName() const
136{
137 return m_bad ;
138}
139
140 bool GNet::Listeners::hasEmpties() const
141{
142 return !m_empties.empty() ;
143}
144
145std::string GNet::Listeners::logEmpties() const
146{
147 return std::string(m_empties.size()==1U?" \"":"s \"").append(G::Str::join("\", \"",m_empties)).append(1U,'"') ;
148}
149
150 const std::vector<int> & GNet::Listeners::fds() const
151{
152 return m_fds ;
153}
154
155 const std::vector<GNet::Address> & GNet::Listeners::fixed() const
156{
157 return m_fixed ;
158}
159
160 const std::vector<GNet::Address> & GNet::Listeners::dynamic() const
161{
162 return m_dynamic ;
163}
164
GNet::Address
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:63
GNet::Address::validStrings
static bool validStrings(std::string_view ip, std::string_view port_string, std::string *reason=nullptr)
Returns true if the combined network-address string and port string is valid.
Definition: gaddress.cpp:398
GNet::Address::parse
static Address parse(std::string_view display_string)
Factory function for any address family.
Definition: gaddress.cpp:178
GNet::Interfaces
A class for getting a list of network interfaces and their addresses.
Definition: ginterfaces.h:48
GNet::Interfaces::addresses
std::vector< Address > addresses(const std::string &name, unsigned int port, int af=AF_UNSPEC) const
Returns addresses bound to the given interface.
Definition: ginterfaces_common.cpp:65
GNet::Interfaces::active
static bool active()
Returns true if the implementation can raise InterfacesHandler events.
Definition: ginterfaces_none.cpp:44
GNet::Listeners::defunct
bool defunct() const
Returns true if no inputs and static.
Definition: glisteners.cpp:106
GNet::Listeners::hasEmpties
bool hasEmpties() const
Returns true if some named interfaces have no addresses.
Definition: glisteners.cpp:140
GNet::Listeners::logEmpties
std::string logEmpties() const
Returns a log-line snippet for hasEmpties().
Definition: glisteners.cpp:145
GNet::Listeners::fds
const std::vector< int > & fds() const
Exposes the list of fd inputs.
Definition: glisteners.cpp:150
GNet::Listeners::Listeners
Listeners(const Interfaces &, const G::StringArray &listener_spec_list, unsigned int port)
Constructor.
Definition: glisteners.cpp:27
GNet::Listeners::idle
bool idle() const
Returns true if no inputs but some interfaces might come up.
Definition: glisteners.cpp:111
GNet::Listeners::noUpdates
bool noUpdates() const
Returns true if some inputs are interfaces but GNet::Interfaces is not active().
Definition: glisteners.cpp:116
GNet::Listeners::fixed
const std::vector< Address > & fixed() const
Exposes the list of address inputs.
Definition: glisteners.cpp:155
GNet::Listeners::dynamic
const std::vector< Address > & dynamic() const
Exposes the list of interface addresses.
Definition: glisteners.cpp:160
GNet::Listeners::badName
std::string badName() const
Returns the first invalid input.
Definition: glisteners.cpp:135
GNet::Listeners::hasBad
bool hasBad() const
Returns true if one or more inputs are invalid.
Definition: glisteners.cpp:130
GNet::StreamSocket::supports
static bool supports(Address::Family)
Returns true if stream sockets can be created with the given the address family.
Definition: gsocket.cpp:448
G::Str::isUInt
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
G::Str::tailMatch
static bool tailMatch(std::string_view in, std::string_view ending) noexcept
Returns true if the string has the given ending (or the given ending is empty).
Definition: gstr.cpp:1352
G::Str::toInt
static int toInt(std::string_view s)
Converts string 's' to an int.
Definition: gstr.cpp:538
G::Str::join
static std::string join(std::string_view sep, const StringArray &strings)
Concatenates an array of strings with separators.
Definition: gstr.cpp:1221
G::Str::fromUInt
static std::string fromUInt(unsigned int ui)
Converts unsigned int 'ui' to a string.
Definition: gstr.h:612
gassert.h
glisteners.h
glog.h
G::StringArray
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstringarray.h:30