E-MailRelay

gsmtpserverbufferin.h
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 gsmtpserverbufferin.h
19///
20
21#ifndef G_SMTP_SERVER_BUFFER_IN_H
22#define G_SMTP_SERVER_BUFFER_IN_H
23
24#include "gdef.h"
25#include "gsmtpserverprotocol.h"
26#include "geventstate.h"
27#include "glinebuffer.h"
28#include "gtimer.h"
29#include "gexception.h"
30#include "gslot.h"
31
32 namespace GSmtp
33{
34 class ServerBufferIn ;
35}
36
37//| \class GSmtp::ServerBufferIn
38/// A helper class for GSmtp::ServerProtocol that does buffering of data
39/// received from the remote peer and apply()s it to the server protocol.
40///
41/// The original SMTP protocol has a simple request/response setup phase
42/// followed by a streaming data transfer phase, so a GNet::LineBuffer
43/// can be used with no risk of overflow. The RFC-2920 PIPELINING extension
44/// develops this by defining request/response batches with a well-defined
45/// batch boundary before the data transfer phase.
46///
47/// RFC-2920 PIPELINING tries to define a size limit for an input batch,
48/// but only in terms of the network layer PDU size -- which is useless
49/// in practice.
50///
51/// Unfortunately the RFC-3030 CHUNKING ("BDAT") extension is underspecified
52/// so there is no batch boundary prior to the data transfer phase. That
53/// means that in the worst case the remote client can start the data
54/// transfer before the setup commands have been fully processed and blow
55/// up the input buffer with megabytes of message body data. Therefore we
56/// have to use network flow control to limit the amount of buffering:
57///
58/// \code
59/// Server::Server() : m_buffer(...)
60/// {
61/// m_buffer.flowSignal().connect( slot(*this,&Server::onFlow) ) ;
62/// }
63/// void Server::onData( p , n )
64/// {
65/// m_buffer.apply(p,n) ;
66/// }
67/// void Server::onFlow( bool on )
68/// {
69/// on ? addReadHandler(m_fd) : dropReadHandler(m_fd) ;
70/// }
71/// \endcode
72///
73 class GSmtp::ServerBufferIn
74{
75 public:
76 G_EXCEPTION( Overflow , tx("server protocol overflow") )
77
78 struct Config /// A configuration structure for GSmtp::ServerBufferIn.
79 {
80 std::size_t input_buffer_soft_limit {G::Limits<>::net_buffer} ; // threshold to apply flow control
81 std::size_t input_buffer_hard_limit {static_cast<std::size_t>(G::Limits<>::net_buffer)*4U} ; // threshold to fail
82 Config & set_input_buffer_soft_limit( std::size_t ) noexcept ;
83 Config & set_input_buffer_hard_limit( std::size_t ) noexcept ;
84 } ;
85
86 ServerBufferIn( GNet::EventState , ServerProtocol & , const Config & ) ;
87 ///< Constructor.
88
89 ~ServerBufferIn() ;
90 ///< Destructor.
91
92 void apply( const char * , std::size_t ) ;
93 ///< Called when raw data is received from the peer. Line
94 ///< buffering is performed and complete lines are
95 ///< apply()ed to the ServerProtocol. If the ServerProtocol
96 ///< cannot accept everything then the residue is queued
97 ///< and re-apply()d transparently.
98 ///<
99 ///< Throws Done at the end of the protocol.
100
101 void expect( std::size_t ) ;
102 ///< Forwards to GNet::LineBuffer::expect().
103
104 std::string head() const ;
105 ///< Returns GNet::LineBufferState::head().
106
107 G::Slot::Signal<bool> & flowSignal() noexcept ;
108 ///< Returns a signal that should be connected to a function
109 ///< that controls network flow control, typically by adding
110 ///< and removing the socket file descriptor from the event
111 ///< loop.
112
113public:
114 ServerBufferIn( const ServerBufferIn & ) = delete ;
115 ServerBufferIn( ServerBufferIn && ) = delete ;
116 ServerBufferIn & operator=( const ServerBufferIn & ) = delete ;
117 ServerBufferIn & operator=( ServerBufferIn && ) = delete ;
118
119private:
120 void applySome( const char * , std::size_t ) ;
121 void onTimeout() ;
122 void onProtocolChange() ;
123 bool overLimit() const ;
124 bool overHardLimit() const ;
125 void flowOn() ;
126 void flowOff() ;
127
128private:
129 ServerProtocol & m_protocol ;
130 Config m_config ;
131 GNet::LineBuffer m_line_buffer ;
132 GNet::Timer<ServerBufferIn> m_timer ;
133 G::Slot::Signal<bool> m_flow_signal ;
134 bool m_flow_on {true} ;
135} ;
136
137 inline GSmtp::ServerBufferIn::Config & GSmtp::ServerBufferIn::Config::set_input_buffer_soft_limit( std::size_t n ) noexcept { input_buffer_soft_limit = n ; return *this ; }
138 inline GSmtp::ServerBufferIn::Config & GSmtp::ServerBufferIn::Config::set_input_buffer_hard_limit( std::size_t n ) noexcept { input_buffer_hard_limit = n ; return *this ; }
139
140#endif
GNet::EventState
A lightweight object containing an ExceptionHandler pointer, optional ExceptionSource pointer and opt...
Definition: geventstate.h:131
GSmtp::ServerBufferIn
A helper class for GSmtp::ServerProtocol that does buffering of data received from the remote peer an...
Definition: gsmtpserverbufferin.h:74
GSmtp::ServerBufferIn::flowSignal
G::Slot::Signal< bool > & flowSignal() noexcept
Returns a signal that should be connected to a function that controls network flow control,...
Definition: gsmtpserverbufferin.cpp:122
GSmtp::ServerBufferIn::head
std::string head() const
Returns GNet::LineBufferState::head().
Definition: gsmtpserverbufferin.cpp:117
GSmtp::ServerBufferIn::~ServerBufferIn
~ServerBufferIn()
Destructor.
Definition: gsmtpserverbufferin.cpp:36
GSmtp::ServerBufferIn::expect
void expect(std::size_t)
Forwards to GNet::LineBuffer::expect().
Definition: gsmtpserverbufferin.cpp:112
GSmtp::ServerBufferIn::apply
void apply(const char *, std::size_t)
Called when raw data is received from the peer.
Definition: gsmtpserverbufferin.cpp:41
GSmtp::ServerBufferIn::ServerBufferIn
ServerBufferIn(GNet::EventState, ServerProtocol &, const Config &)
Constructor.
Definition: gsmtpserverbufferin.cpp:26
GSmtp::ServerProtocol
Implements the SMTP server-side protocol.
Definition: gsmtpserverprotocol.h:80
geventstate.h
gexception.h
glinebuffer.h
gslot.h
gsmtpserverprotocol.h
gtimer.h
GNet
Network classes.
Definition: gdef.h:1243
GSmtp
SMTP classes.
Definition: gadminserver.h:42
G
Low-level classes.
Definition: garg.h:36
G::tx
constexpr const char * tx(const char *p) noexcept
A briefer alternative to G::gettext_noop().
Definition: ggettext.h:84
std
STL namespace.
GSmtp::ServerBufferIn::Config
A configuration structure for GSmtp::ServerBufferIn.
Definition: gsmtpserverbufferin.h:79
G::Limits
A set of compile-time buffer sizes.
Definition: glimits.h:48
G::Slot::Signal< bool >