E-MailRelay

gaddresslocal_unix.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 gaddresslocal_unix.cpp
19///
20
21#include "gdef.h"
22#include "gaddresslocal.h"
23#include "gstr.h"
24#include "gassert.h"
25#include <cstddef> // offsetof
26#include <cstring> // std::memcpy()
27#include <sys/types.h>
28#include <sys/un.h>
29
30 namespace GNet
31{
32 namespace AddressLocalImp
33 {
34 constexpr std::size_t minsize()
35 {
36 #if GCONFIG_HAVE_UDS_LEN
37 return offsetof( sockaddr_un , sun_family ) + sizeof( sockaddr_un::sun_family ) ;
38 #else
39 return sizeof( sockaddr_un::sun_family ) ;
40 #endif
41 }
42 void setsize( sockaddr_un & a ) noexcept
43 {
44 #if GCONFIG_HAVE_UDS_LEN
45 a.sun_len = SUN_LEN( &a ) ; // ie. poffset() + strlen(sun_path)
46 #else
47 GDEF_IGNORE_PARAM( a ) ;
48 #endif
49 }
50 constexpr std::size_t psize() noexcept
51 {
52 return sizeof( sockaddr_un::sun_path ) ;
53 }
54 constexpr std::size_t poffset() noexcept
55 {
56 return offsetof( sockaddr_un , sun_path ) ;
57 }
58 std::size_t strnlen( const char * p , std::size_t limit ) noexcept
59 {
60 std::size_t n = 0U ;
61 for( ; p && *p && n < limit ; ++p )
62 n++ ;
63 return n ;
64 }
65 }
66}
67
68 unsigned short GNet::AddressLocal::af() noexcept
69{
70 return AF_UNIX ;
71}
72
73 int GNet::AddressLocal::domain() noexcept
74{
75 return PF_UNIX ;
76}
77
78GNet::AddressLocal::AddressLocal( std::nullptr_t ) :
79 m_local{} ,
80 m_size(AddressLocalImp::minsize())
81{
82 namespace imp = AddressLocalImp ;
83 m_local.sun_family = af() ;
84 std::memset( m_local.sun_path , 0 , AddressLocalImp::psize() ) ;
85 imp::setsize( m_local ) ;
86}
87
88GNet::AddressLocal::AddressLocal( unsigned int /*port*/ ) :
89 AddressLocal(nullptr)
90{
91}
92
93GNet::AddressLocal::AddressLocal( unsigned int /*port*/ , int /*loopback_overload*/ ) :
94 AddressLocal(nullptr)
95{
96}
97
98GNet::AddressLocal::AddressLocal( const sockaddr * addr , socklen_t len ) :
99 AddressLocal(nullptr)
100{
101 namespace imp = AddressLocalImp ;
102 std::size_t size = static_cast<std::size_t>( len ) ;
103
104 if( addr == nullptr || size < imp::minsize() || size > sizeof(sockaddr_type) )
105 throw Address::Error( "invalid unix domain sockaddr" ) ;
106
107 if( addr->sa_family != af() )
108 throw Address::BadFamily() ;
109
110 std::memcpy( &m_local , addr , size ) ;
111
112 if( size <= imp::poffset() )
113 {
114 // unnamed/unbound address
115 m_size = imp::minsize() ;
116 }
117 else if( G::is_linux() && m_local.sun_path[0] == '\0' )
118 {
119 // abstract address (linux)
120 m_size = size ;
121 }
122 else
123 {
124 // pathname address
125
126 // make sure that sun_path[] is terminated somewhere
127 if( size == sizeof(sockaddr_type) )
128 {
129 const char * p = &m_local.sun_path[0] ;
130 const char * end = p + imp::psize() ;
131 if( std::find( p , end , 0 ) == end )
132 throw Address::Error( "unix domain path too long" ) ;
133 }
134
135 // our additional constraints
136 if( !G::Str::isPrintable( std::string(&m_local.sun_path[0]) ) )
137 throw Address::BadString( "invalid unix domain socket path" ) ;
138
139 // the structure passed in might be sized to beyond the first
140 // NUL, so calculate our own size
141 m_size = imp::poffset() + std::strlen( &m_local.sun_path[0] ) + 1U ;
142 G_ASSERT( m_size <= size ) ;
143
144 imp::setsize( m_local ) ;
145 }
146}
147
148GNet::AddressLocal::AddressLocal( std::string_view host_part ) :
149 AddressLocal(nullptr)
150{
151 namespace imp = AddressLocalImp ;
152
153 if( host_part.empty() || host_part.at(0) != '/' )
154 throw Address::BadString() ;
155
156 if( host_part == "/"_sv || !G::Str::isPrintable(host_part) )
157 throw Address::BadString() ;
158
159 if( host_part.size() >= imp::psize() )
160 throw Address::BadString( "unix domain address too long" ) ;
161
162 std::memcpy( &m_local.sun_path[0] , host_part.data() , host_part.size() ) ;
163 imp::setsize( m_local ) ;
164 m_size = imp::poffset() + host_part.size() + 1U ; // include terminator in m_size (see unix(7))
165}
166
167std::string GNet::AddressLocal::path() const
168{
169 namespace imp = AddressLocalImp ;
170 if( m_size <= imp::poffset() )
171 {
172 return std::string( 1U , '/' ) ; // unbound address displayed as "/" // NOLINT not return {...}
173 }
174 else if( G::is_linux() && m_local.sun_path[0] == '\0' )
175 {
176 return { &m_local.sun_path[0] , m_size-imp::poffset() } ;
177 }
178 else
179 {
180 std::string p = std::string( &m_local.sun_path[0] , imp::strnlen( &m_local.sun_path[0] , std::min(m_size-imp::poffset(),imp::psize()) ) ) ;
181 return p.empty() ? std::string(1U,'/') : p ;
182 }
183}
184
185 void GNet::AddressLocal::setPort( unsigned int /*port*/ )
186{
187}
188
189 bool GNet::AddressLocal::setZone( std::string_view /*ipv6_zone_name_or_scope_id*/ )
190{
191 return true ;
192}
193
194 void GNet::AddressLocal::setScopeId( unsigned long /*ipv6_scope_id*/ )
195{
196}
197
198std::string GNet::AddressLocal::displayString( bool /*ipv6_with_scope*/ ) const
199{
200 return path() ;
201}
202
203std::string GNet::AddressLocal::hostPartString() const
204{
205 return path() ;
206}
207
208std::string GNet::AddressLocal::queryString() const
209{
210 return {} ;
211}
212
213 bool GNet::AddressLocal::validData( const sockaddr * addr , socklen_t len )
214{
215 return addr != nullptr && addr->sa_family == af() && len >= AddressLocalImp::minsize() && len <= sizeof(sockaddr_type) ;
216}
217
218 bool GNet::AddressLocal::validString( std::string_view path , std::string * reason_p )
219{
220 const char * reason = nullptr ;
221 if( path.size() > AddressLocalImp::psize() )
222 reason = "local-domain address too long" ;
223 if( path.empty() )
224 reason = "empty string" ;
225 if( path[0] != '/' )
226 reason = "not an absolute filesystem path" ;
227 if( !G::Str::isPrintable(path) )
228 reason = "invalid characters" ;
229 if( reason && reason_p )
230 *reason_p = std::string( reason ) ;
231 return reason == nullptr ;
232}
233
234 bool GNet::AddressLocal::validStrings( std::string_view host_part , std::string_view /*port_part*/ ,
235 std::string * reason_p )
236{
237 return validString( host_part , reason_p ) ;
238}
239
240#ifndef G_LIB_SMALL
241 bool GNet::AddressLocal::validPort( unsigned int /*port*/ )
242{
243 return true ;
244}
245#endif
246
247 bool GNet::AddressLocal::same( const AddressLocal & other , bool /*ipv6_compare_with_scope*/ ) const
248{
249 G_ASSERT( m_local.sun_family == af() ) ;
250 return
251 m_local.sun_family == other.m_local.sun_family &&
252 m_size == other.m_size &&
253 path() == other.path() ;
254}
255
256 bool GNet::AddressLocal::sameHostPart( const AddressLocal & other ) const
257{
258 return same( other ) ;
259}
260
261 unsigned int GNet::AddressLocal::port() const
262{
263 return 0U ;
264}
265
266 unsigned long GNet::AddressLocal::scopeId( unsigned long default_ ) const
267{
268 return default_ ;
269}
270
271#ifndef G_LIB_SMALL
272 const sockaddr * GNet::AddressLocal::address() const
273{
274 return reinterpret_cast<const sockaddr*>(&m_local) ;
275}
276#endif
277
278sockaddr * GNet::AddressLocal::address()
279{
280 return reinterpret_cast<sockaddr*>(&m_local) ;
281}
282
283socklen_t GNet::AddressLocal::length() const noexcept
284{
285 return m_size ;
286}
287
288 G::StringArray GNet::AddressLocal::wildcards() const
289{
290 return { displayString() } ;
291}
292
293#ifndef G_LIB_SMALL
294 bool GNet::AddressLocal::format( const std::string & )
295{
296 return true ;
297}
298#endif
299
300 bool GNet::AddressLocal::isLocal( std::string & ) const
301{
302 return true ;
303}
304
305 bool GNet::AddressLocal::isLoopback() const
306{
307 return false ;
308}
309
310 bool GNet::AddressLocal::isLinkLocal() const
311{
312 return false ;
313}
314
315 bool GNet::AddressLocal::isUniqueLocal() const
316{
317 return true ;
318}
319
320 bool GNet::AddressLocal::isMulticast() const
321{
322 return false ;
323}
324
325 bool GNet::AddressLocal::isAny() const
326{
327 return path().empty() ;
328}
329
330 unsigned int GNet::AddressLocal::bits() const
331{
332 return 0U ;
333}
334
G::Str::isPrintable
static bool isPrintable(std::string_view s) noexcept
Returns true if every character is 0x20 or above but not 0x7f.
Definition: gstr.cpp:418
gaddresslocal.h
gassert.h
gstr.h
GNet
Network classes.
Definition: gdef.h:1243
G::StringArray
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstringarray.h:30