Flow 1.0.2
Flow project: Full implementation reference.
|
A server socket able to listen on a single Flow port for incoming connections and return peer sockets (Peer_socket objects) to the local user once such connections are established. More...
#include <server_socket.hpp>
Public Types | |
enum class | State { S_LISTENING , S_CLOSING , S_CLOSED } |
State of a Server_socket. More... | |
using | Peer_socket_ptr = boost::shared_ptr< Peer_socket > |
Equivalent to Peer_socket::Ptr, but can't use that due to C++'s circular reference nonsense. More... | |
Public Types inherited from flow::util::Shared_ptr_alias_holder< boost::shared_ptr< Server_socket > > | |
using | Ptr = boost::shared_ptr< Server_socket > |
Short-hand for ref-counted pointer to mutable values of type Target_type::element_type (a-la T* ). More... | |
using | Const_ptr = Const_target_ptr |
Short-hand for ref-counted pointer to immutable values of type Target_type::element_type (a-la T const * ). More... | |
Public Member Functions | |
~Server_socket () override | |
Boring virtual destructor. Note that deletion is to be handled exclusively via shared_ptr , never explicitly. More... | |
State | state () const |
Current State of the socket. More... | |
Node * | node () const |
Node that produced this Server_socket. More... | |
flow_port_t | local_port () const |
The local Flow-protocol port on which this server is or was listening. More... | |
Peer_socket_ptr | accept (Error_code *err_code=0) |
Non-blocking accept: obtain socket for the least recently established not-yet-obtained peer connection on this server. More... | |
template<typename Rep , typename Period > | |
Peer_socket_ptr | sync_accept (const boost::chrono::duration< Rep, Period > &max_wait, bool reactor_pattern=false, Error_code *err_code=0) |
Blocking (synchronous) version of accept(). More... | |
Peer_socket_ptr | sync_accept (bool reactor_pattern=false, Error_code *err_code=0) |
Equivalent to sync_accept(duration::max(), reactor_pattern, err_code) ; i.e., sync_accept() with no user timeout. More... | |
Error_code | disconnect_cause () const |
The error code that perviously caused state() to become State::S_CLOSED, or success code if state is not CLOSED. More... | |
Public Member Functions inherited from flow::util::Null_interface | |
virtual | ~Null_interface ()=0 |
Boring virtual destructor. More... | |
Public Member Functions inherited from flow::log::Log_context | |
Log_context (Logger *logger=0) | |
Constructs Log_context by storing the given pointer to a Logger and a null Component. More... | |
template<typename Component_payload > | |
Log_context (Logger *logger, Component_payload component_payload) | |
Constructs Log_context by storing the given pointer to a Logger and a new Component storing the specified generically typed payload (an enum value). More... | |
Log_context (const Log_context &src) | |
Copy constructor that stores equal Logger* and Component values as the source. More... | |
Log_context (Log_context &&src) | |
Move constructor that makes this equal to src , while the latter becomes as-if default-constructed. More... | |
Log_context & | operator= (const Log_context &src) |
Assignment operator that behaves similarly to the copy constructor. More... | |
Log_context & | operator= (Log_context &&src) |
Move assignment operator that behaves similarly to the move constructor. More... | |
void | swap (Log_context &other) |
Swaps Logger pointers and Component objects held by *this and other . More... | |
Logger * | get_logger () const |
Returns the stored Logger pointer, particularly as many FLOW_LOG_*() macros expect. More... | |
const Component & | get_log_component () const |
Returns reference to the stored Component object, particularly as many FLOW_LOG_*() macros expect. More... | |
Protected Member Functions | |
Server_socket (log::Logger *logger, const Peer_socket_options *child_sock_opts) | |
Constructs object; initializes most values to well-defined (0, empty, etc.) but not necessarily meaningful values. More... | |
Private Types | |
using | Mutex = util::Mutex_recursive |
Short-hand for reentrant mutex type. More... | |
using | Lock_guard = util::Lock_guard< Mutex > |
Short-hand for RAII lock guard of Mutex. More... | |
Private Member Functions | |
Peer_socket_ptr | sync_accept_impl (const Fine_time_pt &wait_until, bool reactor_pattern, Error_code *err_code) |
Same as sync_accept() but uses a Fine_clock-based Fine_duration non-template type for implementation convenience and to avoid code bloat to specify timeout. More... | |
Private Attributes | |
Peer_socket_options const *const | m_child_sock_opts |
Either null or the pointer to a copy of the template Peer_socket_options intended for resulting Peer_socket objects. More... | |
State | m_state |
See state(). Should be set before user gets access to *this . Must not be modified by non-W threads. More... | |
Node * | m_node |
See node(). More... | |
flow_port_t | m_local_port |
See local_port(). More... | |
util::Linked_hash_set< Peer_socket_ptr > | m_unaccepted_socks |
Queue of passively opened sockets in Peer_socket::Int_state::S_ESTABLISHED internal state that have not yet been claimed by the user via *accept() . More... | |
Error_code | m_disconnect_cause |
The Error_code causing this server's move from LISTENING state (if this has occurred); otherwise a clear (success) Error_code. More... | |
Mutex | m_mutex |
This object's mutex. More... | |
boost::unordered_set< Peer_socket_ptr > | m_connecting_socks |
Set of passively opening sockets in pre-ESTABLISHED (so SYN_RCVD?) internal state (and thus are not yet ready to be given out via *accept() ). More... | |
Friends | |
class | Node |
See rationale for friend ing Node in class Server_socket documentation header. More... | |
Related Functions | |
(Note that these are not member functions.) | |
std::ostream & | operator<< (std::ostream &os, const Server_socket *serv) |
Prints string representation of given socket to given standard ostream and returns the latter. More... | |
std::ostream & | operator<< (std::ostream &os, Server_socket::State state) |
Prints string representation of given socket state to given standard ostream and returns the latter. More... | |
Additional Inherited Members | |
Static Public Member Functions inherited from flow::util::Shared_ptr_alias_holder< boost::shared_ptr< Server_socket > > | |
static Ptr | ptr_cast (const From_ptr &ptr_to_cast) |
Provides syntactic-sugary way to perform a static_pointer_cast<> from a compatible smart pointer type From_ptr , typically From_ptr::element_type being in the same class hierarchy as Target_ptr::element_type . More... | |
static Const_ptr | const_ptr_cast (const From_ptr &ptr_to_cast) |
Identical to ptr_cast() but adds const -ness (immutability) to the pointed-to type. More... | |
static Ptr | dynamic_ptr_cast (const From_ptr &ptr_to_cast) |
Equivalent to ptr_cast() but a dynamic_pointer_cast instead of static. More... | |
static Const_ptr | dynamic_const_ptr_cast (const From_ptr &ptr_to_cast) |
Identical to const_ptr_cast() but a dynamic_pointer_cast instead of static. More... | |
A server socket able to listen on a single Flow port for incoming connections and return peer sockets (Peer_socket objects) to the local user once such connections are established.
A given Server_socket can only arise by calling Node::listen(). Node generates a new Server_socket and returns it (factory pattern). Server_socket is not instantiable otherwise. A Server_socket cannot be deleted explicitly by the user and will only be returned via boost::shared_ptr<>
; when both the Node and all user code no longer refers to it, the Server_socket will be destroyed.
Once a Flow-protocol user has a Server_socket object, that object represents a socket in one of the following basic states:
Exactly the following state transitions are possible for a given Server_socket returned by Node:
Note, in particular, that Closed is final; socket cannot move from Closed to Listening. If after an error or valid closing you want to reestablish a server, obtain a new Server_socket from Node's factory. Same rationale as for equivalent design decision in Peer_socket.
Closing means either this side or other side initiated the closing of this server socket for any reason, but Node is still finishing up operations related to that in the background (such as closing in-progress peer connections). Closed means Node has finished any such operations and has disowned the Server_socket.
In either case the only operation Server_socket supports (accept() and derivatives thereof) is impossible in Closing and Closed. Therefore the two states are distinguished for diagnostic/informational purposes only. Generally one should only accept() when Acceptable, and accept() will return an error if the state is Closing or Closed.
Note that a Closing or Closed Server_socket does NOT mean that already accept()ed Peer_socket objects will be in any way affected.
Server_socket::close()
functionality – at least the equivalent of Peer_socket::close_abruptly().Server_socket, like a TCP server socket, stores a queue of fully established peer connections. A Peer_socket is placed onto this internal queue only once its state() == State::S_OPEN (i.e., the connection handshake is finished/successful). Peer_socket objects are then obtained from this queue via the Server_socket::accept() call and its derivatives.
The sync_accept() method is efficient, in that it uses no processor cycles until Acceptable is achieved (i.e., it sleeps until that point). The non-blocking accept() method doesn't sleep/block, however. For a program using it to be efficient it should sleep until Acceptable and only then call accept(), when a Peer_socket is certainly available for immediate acceptance. Moreover, a complex program is likely to want to perform this sleep-and-conditional-wake on a set of several Server_sockets (and/or other sockets) simultaneously (similarly to select()
, epoll*()
, etc.). Use class Event_set for this purpose.
Same as for Node. (Briefly: all operations safe for simultaneous execution on separate or the same object.)
See Peer_socket documentation header. Similar comments apply here.
To prevent node.cpp from being unmanageably large (and also because it makes sense), implementations for Node methods that deal only with an individual Server_socket objects reside in server_socket.cpp (even though they are members of Node, since, again, the logic is all forwarded to Node).
State
to Phase
, as with similar to-do in class Peer_socket doc header. Definition at line 118 of file server_socket.hpp.
|
private |
Short-hand for RAII lock guard of Mutex.
Definition at line 308 of file server_socket.hpp.
|
private |
Short-hand for reentrant mutex type.
We explicitly rely on reentrant behavior, so this isn't "just in case."
Definition at line 305 of file server_socket.hpp.
using flow::net_flow::Server_socket::Peer_socket_ptr = boost::shared_ptr<Peer_socket> |
Equivalent to Peer_socket::Ptr, but can't use that due to C++'s circular reference nonsense.
Definition at line 142 of file server_socket.hpp.
|
strong |
State of a Server_socket.
Enumerator | |
---|---|
S_LISTENING | Future or current accept()s may be possible. A socket in this state may be Acceptable. |
S_CLOSING | No accept()s are or will be possible, but Node is still finishing up the closing operation. |
S_CLOSED | No accept()s are or will be possible, AND Node has disowned the Server_socket. |
Definition at line 131 of file server_socket.hpp.
|
override |
Boring virtual
destructor. Note that deletion is to be handled exclusively via shared_ptr
, never explicitly.
Definition at line 45 of file server_socket.cpp.
References FLOW_LOG_TRACE, and m_child_sock_opts.
|
explicitprotected |
Constructs object; initializes most values to well-defined (0, empty, etc.) but not necessarily meaningful values.
logger | The Logger implementation to use subsequently. |
child_sock_opts | Pointer to a per-socket options struct to copy and store; for each Peer_socket resulting from this Server_socket, the options will be a copy of this copy. If null pointer, then instead the enclosing Node's global per-socket options will be used to produce the copy. |
Definition at line 30 of file server_socket.cpp.
References FLOW_LOG_TRACE.
Referenced by sync_accept_impl().
Peer_socket::Ptr flow::net_flow::Server_socket::accept | ( | Error_code * | err_code = 0 | ) |
Non-blocking accept: obtain socket for the least recently established not-yet-obtained peer connection on this server.
There is a queue (FIFO) of not-yet-claimed connections, and this returns the one at the front of the queue.
If state() is State::S_CLOSING or State::S_CLOSED (i.e., not State::S_LISTENING), this will return null (and an error), even if connections have been queued up. Rationale: BSD sockets act similarly: cannot succeed with accept(s)
, if s
is not listening; also internal implementation is simpler. Anti-rationale: our API is much more amenable to allowing accept()s in that situation; and it would mirror the fact that Peer_socket::receive() can succeed in S_OPEN+S_DISCONNECTING
state. Why rationale > anti-rationale: it's a judgment call, and I'm going with simplicity of implementation at least for now.
err_code | See flow::Error_code docs for error reporting semantics. Note: no available connections is not, in itself, an error. So it's quite possible for null to be returned but *err_code is success. |
sock
with sock->state() == Peer_socket::State::S_OPEN
. If no connections are available (including if bool(*err_code) == true
), returns null pointer. Definition at line 75 of file server_socket.cpp.
References accept(), flow::net_flow::Node::accept(), flow::net_flow::Node::ensure_sock_open(), FLOW_ERROR_EXEC_AND_THROW_ON_ERROR, m_mutex, and m_node.
Referenced by accept().
Error_code flow::net_flow::Server_socket::disconnect_cause | ( | ) | const |
The error code that perviously caused state() to become State::S_CLOSED, or success code if state is not CLOSED.
Note that once it returns non-success, the returned value subsequently will always be the same.
Definition at line 64 of file server_socket.cpp.
References m_disconnect_cause, and m_mutex.
Referenced by flow::net_flow::asio::Server_socket::async_accept_impl().
flow_port_t flow::net_flow::Server_socket::local_port | ( | ) | const |
The local Flow-protocol port on which this server is or was listening.
For a given Server_socket, this will always return the same value, even if CLOSED. However, when CLOSED, the port may be unused or taken by another socket.
Definition at line 70 of file server_socket.cpp.
References m_local_port.
Referenced by operator<<().
Node * flow::net_flow::Server_socket::node | ( | ) | const |
Node that produced this Server_socket.
Definition at line 58 of file server_socket.cpp.
References m_mutex, and m_node.
Referenced by flow::net_flow::asio::Server_socket::async_accept_impl().
Server_socket::State flow::net_flow::Server_socket::state | ( | ) | const |
Current State of the socket.
Definition at line 52 of file server_socket.cpp.
Peer_socket::Ptr flow::net_flow::Server_socket::sync_accept | ( | bool | reactor_pattern = false , |
Error_code * | err_code = 0 |
||
) |
Equivalent to sync_accept(duration::max(), reactor_pattern, err_code)
; i.e., sync_accept() with no user timeout.
err_code | See other sync_accept(). |
reactor_pattern | See other sync_accept(). |
Definition at line 95 of file server_socket.cpp.
References sync_accept_impl().
Server_socket::Peer_socket_ptr flow::net_flow::Server_socket::sync_accept | ( | const boost::chrono::duration< Rep, Period > & | max_wait, |
bool | reactor_pattern = false , |
||
Error_code * | err_code = 0 |
||
) |
Blocking (synchronous) version of accept().
Acts just like accept(), except that if *this
is not immediately Acceptable (i.e., accept() would return null and no error), waits until it is Acceptable (accept() would return either non-null, or null and an error) and returns accept(err_code)
. In reactor_pattern
mode (see arg doc), if it were to otherwise return a non-null Peer_socket::Ptr
, it instead leaves the ready peer socket available for subsequence acceptance and returns null.
If a timeout is specified, and this timeout expires before socket is Acceptable, acts like accept() executed on an un-Acceptable server socket.
These are the possible outcomes.
!reactor_pattern
then the new socket is returned, and no error is returned via *err_code
; otherwise the socket is left available for acceptance, while null is returned, and (similarly to non-reactor-pattern mode) no error is returned via *err_code
.*err_code
is set to reason for connection failure unless null. (If err_code
null, Runtime_error thrown.) The code error::Code::S_WAIT_INTERRUPTED means the wait was interrupted (similarly to POSIX's EINTR
).Note that – if !reactor_pattern
– it is NOT possible to return null and no error.
Tip: Typical types you might use for max_wait
: boost::chrono::milliseconds
, boost::chrono::seconds
, boost::chrono::high_resolution_clock::duration
.
Rep | See boost::chrono::duration documentation (and see above tip). |
Period | See boost::chrono::duration documentation (and see above tip). |
max_wait | The maximum amount of time from now to wait before giving up on the wait and returning. "duration<Rep, Period>::max()" will eliminate the time limit and cause indefinite wait (i.e., no timeout). |
reactor_pattern | If and only if true , and the call successfully waited until server socket became Acceptable, then we return a null pointer and leave the peer socket ready to be accepted by the caller. If false , then in that same situation the socket is accepted and returned. The parameter doesn't affect any other situations. |
err_code | See flow::Error_code docs for error reporting semantics. |
reactor_pattern
mode this may be null, yet indeed a socket is Acceptable (the presence or lack of an error indicates whether that's the case). Definition at line 434 of file server_socket.hpp.
References flow::util::chrono_duration_from_now_to_fine_time_pt(), and sync_accept_impl().
|
private |
Same as sync_accept() but uses a Fine_clock-based Fine_duration non-template type for implementation convenience and to avoid code bloat to specify timeout.
wait_until | See sync_accept(timeout) . This is the absolute time point corresponding to that. "duration<Rep, Period>::max()" maps to the value Fine_time_pt() (Epoch) for this argument. |
reactor_pattern | See sync_accept(). |
err_code | See sync_accept(). |
Definition at line 100 of file server_socket.cpp.
References flow::net_flow::Node::accept(), flow::net_flow::Node::ensure_sock_open(), FLOW_ERROR_EXEC_AND_THROW_ON_ERROR, m_mutex, m_node, flow::net_flow::Event_set::S_SERVER_SOCKET_ACCEPTABLE, Server_socket(), sync_accept_impl(), and flow::net_flow::Node::sync_op().
Referenced by sync_accept(), and sync_accept_impl().
|
friend |
See rationale for friend
ing Node in class Server_socket documentation header.
Definition at line 295 of file server_socket.hpp.
|
related |
Prints string representation of given socket to given standard ostream
and returns the latter.
The representation includes the local endpoint and the hex pointer value.
shared_ptr
forwards ostream
output to the underlying pointer type, so this will affect Ptr
output as well. os | Stream to print to. |
serv | Object to serialize. May be null. |
os
. Definition at line 881 of file server_socket.cpp.
References local_port().
|
related |
Prints string representation of given socket state to given standard ostream
and returns the latter.
os | Stream to print to. |
state | Value to serialize. |
os
. Definition at line 902 of file server_socket.cpp.
|
private |
Either null or the pointer to a copy of the template Peer_socket_options intended for resulting Peer_socket objects.
Null means Peer_socket should use Node::options() as the template instead.
Must be deleted in destructor if not null.
Definition at line 337 of file server_socket.hpp.
Referenced by ~Server_socket().
|
private |
Set of passively opening sockets in pre-ESTABLISHED (so SYN_RCVD?) internal state (and thus are not yet ready to be given out via *accept()
).
This gains meaning only in thread W. This should NOT be accessed outside of thread W and is not protected my a mutex.
Once a socket is acceptable (ESTABLISHED), it is moved from this to m_unaccepted_socks, where it can be claimed by the user. Thus the user never accesses this, and it is maintained by thread W only.
Definition at line 410 of file server_socket.hpp.
|
private |
The Error_code causing this server's move from LISTENING state (if this has occurred); otherwise a clear (success) Error_code.
This starts as success and may move to one non-success value and then never change after that. Graceful closing of the server via close()
is indeed counted as a non-success value for m_disconnect_cause.
As in TCP net-stacks, one cannot recover from a transmission error or termination on the socket (the "error" EWOULDBLOCK
/EAGAIN
does not count), which is why this can only go from success -> non-success and never change after that. (boost.asio error would be would_block
or try_again
when I said EWOUDLBLOCK
/EAGAIN
informally there.)
How to report this to the user: attempting to *accept()
or other operations while m_disconnect_cause is not success => the operation returns this Error_code to the user. Note that even already queued acceptable sockets (m_unaccepted_socks) will no longer be available for acceptance.
This should be success in LISTENING state and failure otherwise.
Since user threads will access this at least via accept(), while thread W may set it when implementing the server socket close, this must be protected by a mutex.
Definition at line 390 of file server_socket.hpp.
Referenced by disconnect_cause().
|
private |
See local_port().
Should be set before user gets access to *this
and not changed afterwards.
const
? Definition at line 352 of file server_socket.hpp.
Referenced by local_port().
|
mutableprivate |
This object's mutex.
The protected items are m_state, m_node, m_unaccepted_socks, sock->m_originating_serv
for each sock
in m_unaccepted_socks, and m_disconnect_cause.
Definition at line 397 of file server_socket.hpp.
Referenced by accept(), disconnect_cause(), node(), state(), and sync_accept_impl().
|
private |
See node().
Should be set before user gets access to *this
and not changed, except to 0 when state is S_CLOSED. Must not be modified by non-W threads.
Definition at line 346 of file server_socket.hpp.
Referenced by accept(), node(), and sync_accept_impl().
|
private |
See state(). Should be set before user gets access to *this
. Must not be modified by non-W threads.
Definition at line 340 of file server_socket.hpp.
Referenced by state().
|
private |
Queue of passively opened sockets in Peer_socket::Int_state::S_ESTABLISHED internal state that have not yet been claimed by the user via *accept()
.
back()
is the next socket to be accepted (i.e., the one that established connection longest ago). This is not the more restricted queue<>
, because sometimes we want to remove things from the middle of it on error. It is not a list<>
, because we sometimes (on error) need to erase items from the middle which requires a lookup by stored Peer_socket_ptr value which would be linear-time in a plain list<>
.
Write-accessible from thread W and user threads (in accept()
) and must be protected by a mutex.
Definition at line 366 of file server_socket.hpp.