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
27GNet::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
53int 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
71int 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
82void 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
91bool GNet::Listeners::isAddress( const std::string & s , unsigned int port )
92{
93 return Address::validStrings( s , G::Str::fromUInt(port) ) ;
94}
95
96GNet::Address GNet::Listeners::address( const std::string & s , unsigned int port )
97{
98 return Address::parse( s , port ) ;
99}
100
101bool GNet::Listeners::empty() const
102{
103 return m_fds.empty() && m_fixed.empty() && m_dynamic.empty() ;
104}
105
107{
108 return empty() && !Interfaces::active() ;
109}
110
112{
113 return empty() && hasEmpties() && Interfaces::active() ;
114}
115
117{
118 return !m_used.empty() && !Interfaces::active() ;
119}
120
121bool 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
131{
132 return !m_bad.empty() ;
133}
134
135std::string GNet::Listeners::badName() const
136{
137 return m_bad ;
138}
139
141{
142 return !m_empties.empty() ;
143}
144
146{
147 return std::string(m_empties.size()==1U?" \"":"s \"").append(G::Str::join("\", \"",m_empties)).append(1U,'"') ;
148}
149
150const std::vector<int> & GNet::Listeners::fds() const
151{
152 return m_fds ;
153}
154
155const std::vector<GNet::Address> & GNet::Listeners::fixed() const
156{
157 return m_fixed ;
158}
159
160const std::vector<GNet::Address> & GNet::Listeners::dynamic() const
161{
162 return m_dynamic ;
163}
164
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:63
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
static Address parse(std::string_view display_string)
Factory function for any address family.
Definition: gaddress.cpp:178
A class for getting a list of network interfaces and their addresses.
Definition: ginterfaces.h:48
std::vector< Address > addresses(const std::string &name, unsigned int port, int af=AF_UNSPEC) const
Returns addresses bound to the given interface.
static bool active()
Returns true if the implementation can raise InterfacesHandler events.
bool defunct() const
Returns true if no inputs and static.
Definition: glisteners.cpp:106
bool hasEmpties() const
Returns true if some named interfaces have no addresses.
Definition: glisteners.cpp:140
std::string logEmpties() const
Returns a log-line snippet for hasEmpties().
Definition: glisteners.cpp:145
const std::vector< int > & fds() const
Exposes the list of fd inputs.
Definition: glisteners.cpp:150
Listeners(const Interfaces &, const G::StringArray &listener_spec_list, unsigned int port)
Constructor.
Definition: glisteners.cpp:27
bool idle() const
Returns true if no inputs but some interfaces might come up.
Definition: glisteners.cpp:111
bool noUpdates() const
Returns true if some inputs are interfaces but GNet::Interfaces is not active().
Definition: glisteners.cpp:116
const std::vector< Address > & fixed() const
Exposes the list of address inputs.
Definition: glisteners.cpp:155
const std::vector< Address > & dynamic() const
Exposes the list of interface addresses.
Definition: glisteners.cpp:160
std::string badName() const
Returns the first invalid input.
Definition: glisteners.cpp:135
bool hasBad() const
Returns true if one or more inputs are invalid.
Definition: glisteners.cpp:130
static bool supports(Address::Family)
Returns true if stream sockets can be created with the given the address family.
Definition: gsocket.cpp:448
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 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
static int toInt(std::string_view s)
Converts string 's' to an int.
Definition: gstr.cpp:538
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 fromUInt(unsigned int ui)
Converts unsigned int 'ui' to a string.
Definition: gstr.h:612
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstringarray.h:30