E-MailRelay

gserver.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 gserver.cpp
19///
20
21#include "gdef.h"
22#include "gserver.h"
23#include "gnetdone.h"
24#include "gmonitor.h"
25#include "geventloggingcontext.h"
26#include "gfile.h"
27#include "gcleanup.h"
28#include "glimits.h"
29#include "groot.h"
30#include "gscope.h"
31#include "gtest.h"
32#include "glog.h"
33#include "gassert.h"
34#include <algorithm>
35
36 GNet::Server::Server( EventState es , Descriptor fd ,
37 const ServerPeer::Config & server_peer_config , const Config & server_config ) :
38 m_es(es) ,
39 m_config(server_config) ,
40 m_server_peer_config(server_peer_config) ,
41 m_socket(StreamSocket::Listener(),fd,m_config.stream_socket_config)
42{
43 G_DEBUG( "GNet::Server::ctor: listening on socket " << m_socket.asString()
44 << " with address " << m_socket.getLocalAddress().displayString() ) ;
45 m_socket.listen() ;
46 m_socket.addReadHandler( *this , m_es ) ;
47 Monitor::addServer( *this ) ;
48}
49
50 GNet::Server::Server( EventState es , const Address & listening_address ,
51 const ServerPeer::Config & server_peer_config , const Config & server_config ) :
52 m_es(es) ,
53 m_config(server_config) ,
54 m_server_peer_config(server_peer_config) ,
55 m_socket(listening_address.family(),StreamSocket::Listener(),m_config.stream_socket_config)
56{
57 G_DEBUG( "GNet::Server::ctor: listening on socket " << m_socket.asString()
58 << " with address " << listening_address.displayString() ) ;
59
60 bool uds = listening_address.family() == Address::Family::local ;
61 if( uds )
62 {
63 bool open = m_config.uds_open_permissions ;
64 using Mode = G::Process::Umask::Mode ;
65 G::Root claim_root( false ) ; // group ownership from the effective group-id
66 G::Process::Umask set_umask( open ? Mode::Open : Mode::Tighter ) ;
67 m_socket.bind( listening_address ) ;
68 }
69 else
70 {
71 G::Root claim_root ;
72 m_socket.bind( listening_address ) ;
73 }
74
75 m_socket.listen() ;
76 m_socket.addReadHandler( *this , m_es ) ;
77 Monitor::addServer( *this ) ;
78
79 if( uds )
80 {
81 std::string path = listening_address.hostPartString() ;
82 if( path.size() > 1U && path.at(0U) == '/' )
83 {
84 G::Cleanup::add( G::File::cleanup , G::Cleanup::arg(G::Path(path)) ) ;
85 }
86 }
87}
88
89 GNet::Server::~Server()
90{
91 Monitor::removeServer( *this ) ;
92}
93
94 GNet::Address GNet::Server::address() const
95{
96 bool with_scope = true ; // was false
97 Address result = m_socket.getLocalAddress() ;
98 if( with_scope )
99 result.setScopeId( m_socket.getBoundScopeId() ) ;
100 return result ;
101}
102
103 void GNet::Server::readEvent()
104{
105 // read-event-on-listening-port => new connection to accept
106 G_DEBUG( "GNet::Server::readEvent: " << this ) ;
107
108 // accept the connection
109 //
110 ServerPeerInfo peer_info( this , m_server_peer_config ) ;
111 accept( peer_info ) ;
112 Address peer_address = peer_info.m_address ;
113 G_DEBUG( "GNet::Server::readEvent: new connection from " << peer_address.displayString()
114 << " on " << peer_info.m_socket->asString() ) ;
115
116 // change the logging context asap to reflect the server peer object
117 // being created (esp. if it sends an initial server greeting)
118 //
119 GNet::EventLoggingContext inner( m_es ,
120 ServerPeer::eventLoggingString(peer_address,m_server_peer_config) ) ;
121
122 // create the peer object -- newPeer() implementations will normally catch
123 // their exceptions and return null to avoid terminating the server -- peer
124 // objects are given this object as their exception handler so we get
125 // to delete them when they throw -- the EventState tuple is passed as
126 // 'unbound' to force the peer object to set themselves as the exception
127 // source
128 //
129 std::unique_ptr<ServerPeer> peer = newPeer( m_es.eh(this).unbound() , std::move(peer_info) ) ;
130
131 // commit or roll back
132 if( peer == nullptr )
133 {
134 G_WARNING( "GNet::Server::readEvent: connection rejected from " << peer_address.displayString() ) ;
135 }
136 else
137 {
138 G_DEBUG( "GNet::Server::readEvent: new connection accepted" ) ;
139 m_peer_list.push_back( std::shared_ptr<ServerPeer>(peer.release()) ) ;
140 }
141}
142
143 void GNet::Server::accept( ServerPeerInfo & peer_info )
144{
145 AcceptInfo accept_info ;
146 {
147 G::Root claim_root ;
148 accept_info = m_socket.accept() ;
149 }
150 peer_info.m_address = accept_info.address ;
151 peer_info.m_socket = std::move( accept_info.socket_ptr ) ;
152}
153
154 void GNet::Server::onException( ExceptionSource * esrc , std::exception & e , bool done )
155{
156 G_DEBUG( "GNet::Server::onException: exception=[" << e.what() << "] esrc=[" << static_cast<void*>(esrc) << "]" ) ;
157 bool handled = false ;
158 if( esrc != nullptr )
159 {
160 for( auto list_p = m_peer_list.begin() ; list_p != m_peer_list.end() ; ++list_p )
161 {
162 if( (*list_p).get() == esrc ) // implicit ServerPeer/ExceptionSource static cast
163 {
164 std::shared_ptr<ServerPeer> peer_p = *list_p ;
165 m_peer_list.erase( list_p ) ; // remove first, in case onDelete() throws
166 (*peer_p).doOnDelete( e.what() , done ) ;
167 handled = true ;
168 break ; // ServerPeer deleted here
169 }
170 }
171 }
172 if( !handled )
173 {
174 G_WARNING( "GNet::Server::onException: unhandled exception: " << e.what() ) ;
175 throw ; // should never get here -- rethrow just in case
176 }
177}
178
179 void GNet::Server::serverCleanup()
180{
181 m_peer_list.clear() ;
182}
183
184 bool GNet::Server::hasPeers() const
185{
186 return !m_peer_list.empty() ;
187}
188
189std::vector<std::weak_ptr<GNet::ServerPeer>> GNet::Server::peers()
190{
191 using Peers = std::vector<std::weak_ptr<ServerPeer>> ;
192 Peers result ;
193 result.reserve( m_peer_list.size() ) ;
194 for( auto & peer : m_peer_list )
195 result.push_back( std::weak_ptr<ServerPeer>(peer) ) ;
196 return result ;
197}
198
199 void GNet::Server::writeEvent()
200{
201 G_DEBUG( "GNet::Server::writeEvent" ) ;
202}
203
204// ===
205
206GNet::ServerPeerInfo::ServerPeerInfo( Server * server , ServerPeer::Config server_peer_config ) :
207 m_address(Address::defaultAddress()) ,
208 m_server_peer_config(server_peer_config) ,
209 m_server(server)
210{
211}
212
GNet::Address
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:63
GNet::Address::setScopeId
Address & setScopeId(unsigned long)
Sets the scope-id.
Definition: gaddress.cpp:238
GNet::Address::displayString
std::string displayString(bool with_scope_id=false) const
Returns a printable string that represents the transport address.
Definition: gaddress.cpp:356
GNet::Address::hostPartString
std::string hostPartString() const
Returns a printable string that represents the network address.
Definition: gaddress.cpp:365
GNet::Address::family
Family family() const noexcept
Returns the address family enumeration.
Definition: gaddress.cpp:474
GNet::Descriptor
A class that encapsulates a network socket file descriptor and an associated windows event handle.
Definition: gdescriptor.h:37
GNet::EventLoggingContext
A class that sets the G::LogOuput::context() while in scope.
Definition: geventloggingcontext.h:38
GNet::EventState
A lightweight object containing an ExceptionHandler pointer, optional ExceptionSource pointer and opt...
Definition: geventstate.h:131
GNet::Listener
An interface for a network listener.
Definition: glistener.h:37
GNet::Monitor::addServer
static void addServer(const Listener &server)
Adds a server.
Definition: gmonitor.cpp:141
GNet::Monitor::removeServer
static void removeServer(const Listener &server) noexcept
Removes a server.
Definition: gmonitor.cpp:150
GNet::ServerPeerInfo
A move-only structure used in GNet::Server::newPeer() and containing the new socket.
Definition: gserver.h:142
GNet::Server::~Server
~Server() override
Destructor.
Definition: gserver.cpp:89
GNet::Server::address
Address address() const override
Returns the listening address.
Definition: gserver.cpp:94
GNet::Server::hasPeers
bool hasPeers() const
Returns true if peers() is not empty.
Definition: gserver.cpp:184
GNet::Server::Server
Server(EventState, const Address &listening_address, const ServerPeer::Config &, const Config &)
Constructor.
Definition: gserver.cpp:50
GNet::Server::peers
std::vector< std::weak_ptr< GNet::ServerPeer > > peers()
Returns the list of ServerPeer objects.
Definition: gserver.cpp:189
GNet::Server::serverCleanup
void serverCleanup()
Should be called by the most-derived class's destructor in order to trigger early deletion of peer ob...
Definition: gserver.cpp:179
GNet::SocketBase::asString
std::string asString() const
Returns the socket handle as a string.
Definition: gsocket.cpp:218
GNet::SocketBase::addReadHandler
void addReadHandler(EventHandler &, EventState)
Adds this socket to the event source list so that the given handler receives read events.
Definition: gsocket.cpp:155
GNet::Socket::bind
void bind(const Address &)
Binds the socket with the given address.
Definition: gsocket.cpp:248
GNet::Socket::listen
void listen()
Starts the socket listening on the bound address for incoming connections or incoming datagrams.
Definition: gsocket.cpp:320
GNet::Socket::getLocalAddress
Address getLocalAddress() const
Retrieves the local address of the socket.
Definition: gsocket.cpp:343
GNet::StreamSocket
A derivation of GNet::Socket for a stream socket.
Definition: gsocket.h:356
G::Cleanup::arg
static Arg arg(const char *)
Duplicates a c-string for add().
Definition: gcleanup_unix.cpp:117
G::Cleanup::add
static void add(Fn, Arg arg)
Adds the given handler to the list of handlers that are to be called when the process terminates abno...
Definition: gcleanup_unix.cpp:94
G::File::cleanup
static bool cleanup(const Cleanup::Arg &path_arg) noexcept
Deletes the file.
Definition: gfile_unix.cpp:172
G::Path
A Path object represents a file system path.
Definition: gpath.h:82
G::Process::Umask
Used to temporarily modify the process umask.
Definition: gprocess.h:197
G::Root
A class which acquires the process's special privileges on construction and releases them on destruct...
Definition: groot.h:52
gassert.h
gcleanup.h
geventloggingcontext.h
gfile.h
glimits.h
glog.h
gmonitor.h
gnetdone.h
groot.h
gscope.h
gserver.h
gtest.h
GNet::ServerPeer::Config
A configuration structure for GNet::ServerPeer.
Definition: gserverpeer.h:64
GNet::Server::Config
A configuration structure for GNet::Server.
Definition: gserver.h:56