Flow 1.0.0
Flow project: Public API.
Public Types | Public Member Functions | Protected Member Functions | Related Functions | List of all members
flow::net_flow::Server_socket Class 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>

Inheritance diagram for flow::net_flow::Server_socket:
[legend]
Collaboration diagram for flow::net_flow::Server_socket:
[legend]

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.
 
- 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*).
 
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 *).
 

Public Member Functions

 ~Server_socket () override
 Boring virtual destructor. Note that deletion is to be handled exclusively via shared_ptr, never explicitly.
 
State state () const
 Current State of the socket. More...
 
Nodenode () 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_contextoperator= (const Log_context &src)
 Assignment operator that behaves similarly to the copy constructor. More...
 
Log_contextoperator= (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...
 
Loggerget_logger () const
 Returns the stored Logger pointer, particularly as many FLOW_LOG_*() macros expect. More...
 
const Componentget_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...
 

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...
 

Detailed Description

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.

Life cycle of a Server_socket

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.

Todo:
Implement Server_socket::close() functionality – at least the equivalent of Peer_socket::close_abruptly().

Accept queue

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.

Efficiently accept()ing

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.

Thread safety

Same as for Node. (Briefly: all operations safe for simultaneous execution on separate or the same object.)

Member Enumeration Documentation

◆ State

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.

Constructor & Destructor Documentation

◆ Server_socket()

flow::net_flow::Server_socket::Server_socket ( log::Logger logger,
const Peer_socket_options child_sock_opts 
)
explicitprotected

Constructs object; initializes most values to well-defined (0, empty, etc.) but not necessarily meaningful values.

Parameters
loggerThe Logger implementation to use subsequently.
child_sock_optsPointer 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.

Member Function Documentation

◆ accept()

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.

Todo:
Reconsider allowing successful accept() in State::S_CLOSING state?
Parameters
err_codeSee 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.
Returns
A Peer_socket sock with sock->state() == Peer_socket::State::S_OPEN. If no connections are available (including if bool(*err_code) == true), returns null pointer.

◆ disconnect_cause()

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.

Returns
Ditto.

◆ local_port()

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.

Returns
See above.

◆ node()

Node * flow::net_flow::Server_socket::node ( ) const

Node that produced this Server_socket.

Returns
Pointer to (guaranteed valid) Node; 0 if state is S_CLOSED.

◆ state()

Server_socket::State flow::net_flow::Server_socket::state ( ) const

Current State of the socket.

Returns
Current state of the socket.

◆ sync_accept() [1/2]

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.

Parameters
err_codeSee other sync_accept().
reactor_patternSee other sync_accept().
Returns
See other sync_accept().

◆ sync_accept() [2/2]

template<typename Rep , typename Period >
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.

Error handling

These are the possible outcomes.

  1. Connection succeeds before the given timeout expires (or succeeds, if no timeout given). Socket is at least Writable at time of return. If !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.
  2. Connection fails before the given timeout expires (or fails, if no timeout given). null is returned, *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).
  3. A user timeout is given, and the connection does not succeed before it expires. Output semantics are the same as in 2, with the specific code error::Code::S_WAIT_USER_TIMEOUT. (Rationale: consistent with sync_receive(), sync_send() behavior.)

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.

See also
The version of sync_accept() with no timeout.
Template Parameters
RepSee boost::chrono::duration documentation (and see above tip).
PeriodSee boost::chrono::duration documentation (and see above tip).
Parameters
max_waitThe 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_patternIf 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_codeSee flow::Error_code docs for error reporting semantics.
Returns
Reference-counted pointer to new Server_socket; or an empty pointer (essentially null). Reminder that in 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).

Friends And Related Function Documentation

◆ operator<<() [1/2]

std::ostream & operator<< ( std::ostream &  os,
const Server_socket serv 
)
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.

Note
shared_ptr forwards ostream output to the underlying pointer type, so this will affect Ptr output as well.
Parameters
osStream to print to.
servObject to serialize. May be null.
Returns
os.

◆ operator<<() [2/2]

std::ostream & operator<< ( std::ostream &  os,
Server_socket::State  state 
)
related

Prints string representation of given socket state to given standard ostream and returns the latter.

Parameters
osStream to print to.
stateValue to serialize.
Returns
os.

The documentation for this class was generated from the following files: