Flow 1.0.0
Flow project: Public API.
|
A peer (non-server) socket operating over the Flow network protocol, with optional stream-of-bytes and reliability support. More...
#include <peer_socket.hpp>
Public Types | |
enum class | State { S_OPEN , S_CLOSED } |
State of a Peer_socket. More... | |
enum class | Open_sub_state { S_CONNECTING , S_CONNECTED , S_DISCONNECTING } |
The sub-state of a Peer_socket when state is State::S_OPEN. More... | |
Public Types inherited from flow::util::Shared_ptr_alias_holder< boost::shared_ptr< Peer_socket > > | |
using | Ptr = boost::shared_ptr< Peer_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 | |
~Peer_socket () override | |
Boring virtual destructor. Note that deletion is to be handled exclusively via shared_ptr , never explicitly. | |
State | state (Open_sub_state *open_sub_state=0) const |
Current State of the socket. More... | |
Node * | node () const |
Node that produced this Peer_socket. More... | |
const Remote_endpoint & | remote_endpoint () const |
Intended other side of the connection (regardless of success, failure, or current State). More... | |
flow_port_t | local_port () const |
The local Flow-protocol port chosen by the Node (if active or passive open) or user (if passive open) for this side of the connection. More... | |
size_t | get_connect_metadata (const boost::asio::mutable_buffer &buffer, Error_code *err_code=0) const |
Obtains the serialized connect metadata, as supplied by the user during the connection handshake. More... | |
template<typename Const_buffer_sequence > | |
size_t | send (const Const_buffer_sequence &data, Error_code *err_code=0) |
Sends (adds to the Send buffer) the given bytes of data up to a maximum internal buffer size; and asynchronously sends them to the other side. More... | |
template<typename Rep , typename Period , typename Const_buffer_sequence > | |
size_t | sync_send (const Const_buffer_sequence &data, const boost::chrono::duration< Rep, Period > &max_wait, Error_code *err_code=0) |
Blocking (synchronous) version of send(). More... | |
template<typename Rep , typename Period > | |
bool | sync_send (const boost::asio::null_buffers &, const boost::chrono::duration< Rep, Period > &max_wait, Error_code *err_code=0) |
sync_send() operating in null_buffers mode, wherein – if Writable state is reached – the actual data are not moved out of any buffer, leaving that to the caller to do if desired. More... | |
template<typename Const_buffer_sequence > | |
size_t | sync_send (const Const_buffer_sequence &data, Error_code *err_code=0) |
Equivalent to sync_send(data, duration::max(), err_code) ; i.e., sync_send() with no timeout. More... | |
bool | sync_send (const boost::asio::null_buffers &, Error_code *err_code=0) |
Equivalent to sync_send(null_buffers(), duration::max(), err_code) ; i.e., sync_send(null_buffers) with no timeout. More... | |
template<typename Mutable_buffer_sequence > | |
size_t | receive (const Mutable_buffer_sequence &target, Error_code *err_code=0) |
Receives (consumes from the Receive buffer) bytes of data, up to a given maximum cumulative number of bytes as inferred from size of provided target buffer sequence. More... | |
template<typename Rep , typename Period , typename Mutable_buffer_sequence > | |
size_t | sync_receive (const Mutable_buffer_sequence &target, const boost::chrono::duration< Rep, Period > &max_wait, Error_code *err_code=0) |
Blocking (synchronous) version of receive(). More... | |
template<typename Rep , typename Period > | |
bool | sync_receive (const boost::asio::null_buffers &, const boost::chrono::duration< Rep, Period > &max_wait, Error_code *err_code=0) |
sync_receive() operating in null_buffers mode, wherein – if Readable state is reached – the actual data are not moved into any buffer, leaving that to the caller to do if desired. More... | |
template<typename Mutable_buffer_sequence > | |
size_t | sync_receive (const Mutable_buffer_sequence &target, Error_code *err_code=0) |
Equivalent to sync_receive(target, duration::max(), err_code) ; i.e., sync_receive() with no timeout. More... | |
bool | sync_receive (const boost::asio::null_buffers &, Error_code *err_code=0) |
Equivalent to sync_receive(null_buffers(), duration::max(), err_code) ; i.e., sync_receive(null_buffers) with no timeout. More... | |
void | close_abruptly (Error_code *err_code=0) |
Acts as if fatal error error::Code::S_USER_CLOSED_ABRUPTLY has been discovered on the connection. More... | |
bool | set_options (const Peer_socket_options &opts, Error_code *err_code=0) |
Dynamically replaces the current options set (options()) with the given options set. More... | |
Peer_socket_options | options () const |
Copies this socket's option set and returns that copy. More... | |
Peer_socket_info | info () const |
Returns a structure containing the most up-to-date stats about this connection. More... | |
size_t | max_block_size () const |
The maximum number of bytes of user data per received or sent packet on this connection. 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 | |
Peer_socket (log::Logger *logger_ptr, util::Task_engine *task_engine, const Peer_socket_options &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 Peer_socket *sock) |
Prints string representation of given socket 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< Peer_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 peer (non-server) socket operating over the Flow network protocol, with optional stream-of-bytes and reliability support.
Reliability is enabled or disabled via a socket option, Peer_socket_options::m_st_rexmit_on, at socket creation. Use unreliable mode with care – see send() method doc header for details.
A given Peer_socket can arise either by connecting to Server_socket on a Node (Node::connect() or Node::sync_connect()), or by listening on a Node's Server_socket and accepting such a connection (Server_socket::accept() or Server_socket::sync_accept()). In all cases, Node or Server_socket generates a new Peer_socket and returns it (factory pattern). Peer_socket is not instantiable otherwise. A Peer_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 Peer_socket will be destroyed.
Once a net_flow
user has a Peer_socket object, that object represents a socket in one of the following basic states:
Open.Connecting means means Node initiated a connect to the given server, and this is in progress. Open.Connected means the connection to the other Node is fully functional. Open.Disconnecting means either our side or the other side has initiated a clean or abrupt disconnect, but it is not yet entirely finished (background handshaking is happening, you have not read all available data or sent all queued data, etc.).
In either case, reading and writing may or may not be possible at a given time, depending on the state of the internal buffers and the data having arrived on the logical connection. Thus all Open sub-states can and often should be treated the same way in a typical Flow-protocol-using algorithm: simply determine when the Peer_socket is Readable, and read; and similarly for Writable and write. Thus the sub-states are distinguished for informational/diagnostic purposes only, as user reading/writing logic in these states should usually be identical.
close_final()
and close_start()
, but those are just ideas and may be replaced with timeout, or nothing. At this time, the only closing supported is abrupt close due to error or abrupt close via close_abruptly().Closed means that the Peer_socket has become disconnected, and no data can possibly be received or sent, AND that Node has no more background internal operations to perform and has disowned the Peer_socket. In other words, a Closed Peer_socket is entirely dead.
Exactly the following state transitions are possible for a given Peer_socket returned by Node:
Note, in particular, that Closed is final; socket cannot move from Closed to Open. If after an error or valid disconnection you want to reestablish a connection, obtain a new Peer_socket from Node's factories. Rationale (subject to change): this cuts down on state having to be tracked inside a Peer_socket, while the interface becomes simpler without much impact on usability. Anti-rationale: contradicts BSD socket and boost.asio established practices; potentially more resource-intensive/slower in the event of errors and disconnects. Why IMO rationale > anti-rationale: it's simpler, and the potential problems do not appear immediately serious; added statefulness can be added later if found desirable.
Receving, sending, and buffers: Peer_socket, like a TCP socket, has a Receive buffer (a/k/a FIFO queue of bytes) of some maximum size and a Send buffer (a/k/a FIFO queue of bytes) of some maximum size. They are typically not directly exposed via the interface, but their existence affects documented behavior. I formally describe them here, but generally they work similarly to TCP socket Send/Receive buffers.
The Receive buffer: Contains bytes asynchronously received on the connection that have not yet been removed with a *receive()
method. Any bytes that asynchronously arrive on the connection are asynchronously stored to the buffer on the other side of the buffer in a queued fashion.
The Send buffer: Contains bytes intended to be asynchronously sent on the connection that have been placed there by a *send()
method but not yet sent on the connection. Any bytes that are asynchronously sent on the connection are asynchronously removed from the buffer on the other side of the buffer in a queued fashion.
With that in mind, here are the definitions of Readable and Writable while state is Open:
close_final()
they're not interested in reading further.Note that neither definition really cares about the state of the network connection (e.g., could bytes actually be sent over the network at the moment?). There is one caveat: A socket is not Writable until Open.Connecting state is transitioned away from; this prevents user from buffering up send data before the connection is ready. (Allowing that would not necessarily be wrong, but I'm taking a cue from BSD socket semantics on this, as they seem to be convenient.)
In Open, the following archetypal operations are provided. (In Closed all immediately fail; in Open.Disconnecting some immediately fail if close*()
has been called.) Let R be the current size of data in the Receive buffer, and S be the available space for data in the Send buffer.
receive(N)
. If Readable, return to caller min(N, R)
oldest data to have been received from the other side, and remove them from Receive buffer. Otherwise do nothing.send(N)
. If Writable, take from caller min(N, S)
data to be appended to the Send buffer and, when possible, sent to the other side. Otherwise do nothing.sync_receive(N)
. If Readable, receive(N)
. Otherwise sleep until Readable, then receive(N)
.sync_send(N)
. If Writable, send(N)
. Otherwise sleep until Writable, then send(N)
.These are similar to TCP Receive and Send APIs in non-blocking mode, and TCP Receive and Send APIs in blocking mode, respectively. There may be other similarly themed methods, but all use these as semantic building blocks.
To understand the order of events, one can think of a disconnect-causing event (like a graceful close initiation from the remote socket) as a piece of data itself. Thus, for example, if 5 bytes are received and placed into the Receive buffer without being read by the user, and then a connection close is detected, the socket will be Readable until the 5 bytes have been receive()ed, and the next receive() (or send()) would yield the error, since that's the order things happened. Similarly, suppose you've sent 5 bytes, but they haven't been yet sent over the wire and are sitting in the Send buffer. Then you trigger a graceful connection close. First the 5 bytes will be sent if possible, and then the closing procedure will actually begin.
Abrupt closes such as connection resets may force both buffers to be immediately emptied without giving to the user or writing to the other side, so that the above rule does not have to apply. Typically a connection reset means the socket is immediately unusable no matter what was in the buffers at the time, per BSD socket semantics.
The sync_*
() methods are efficient, in that they use no processor cycles until Readable or Writable is achieved (i.e., they sleep until that point). The non-blocking versions don't sleep/block, however. For a program using them to be efficient it should sleep until Readable or Writable and only then call receive()/send(), when data are certainly available for immediate reading or writing. Moreover, a complex program is likely to want to perform this sleep-and-conditional-wake on a set of several Peer_socket objects 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.)
|
strong |
The sub-state of a Peer_socket when state is State::S_OPEN.
Enumerator | |
---|---|
S_CONNECTING | This Peer_socket was created through an active connect (Node::connect() and the like), and the connection to the remote Node is currently being negotiated by this socket's Node. A socket in this state may be Writable but cannot be Readable. However, except for diagnostic purposes, this state should generally be treated the same as S_CONNECTED. |
S_CONNECTED | This Peer_socket was created through a passive connect (Node::accept() and the like) or an active connect (Node::connect() and the like), and the connection is (as far this socket's Node knows) set up and functioning. A socket in this state may be Writable or Readable. |
S_DISCONNECTING | This Peer_socket was created through a passive connect (Node::accept() and the like) or an active connect (Node::connect() and the like), but since then either an active close, passive close, or an error has begun to close the connection, but data may still possibly arrive and be Readable; also data may have been "sent" but still sitting in the Send buffer and needs to be sent over the network. A socket in this state may be Readable but cannot be Writable. This implies that a non-S_CLOSED socket may be, at a lower level, disconnected. For example, say there are 5 bytes in the Receive buffer, and the other side sends a graceful disconnect packet to this socket. This means the connection is finished, but the user can still receive() the 5 bytes (without blocking). Then state will remain S_OPEN.S_DISCONNECTING until the last of the 5 bytes is received (gone from the buffer); at this point state may change to S_CLOSED (pending any other work Node must do to be able to disown the socket). |
|
strong |
State of a Peer_socket.
Enumerator | |
---|---|
S_OPEN | Future reads or writes may be possible. A socket in this state may be Writable or Readable. |
S_CLOSED | Neither future reads nor writes are possible, AND Node has disowned the Peer_socket. |
|
explicitprotected |
Constructs object; initializes most values to well-defined (0, empty, etc.) but not necessarily meaningful values.
logger_ptr | The Logger implementation to use subsequently. |
task_engine | IO service for the timer(s) stored as data member(s). |
opts | The options set to copy into this Peer_socket and use subsequently. |
void flow::net_flow::Peer_socket::close_abruptly | ( | Error_code * | err_code = 0 | ) |
Acts as if fatal error error::Code::S_USER_CLOSED_ABRUPTLY has been discovered on the connection.
Does not block.
Post-condition: state() == State::S_CLOSED
. Additionally, assuming no loss on the network, the other side will close the connection with error error::Code::S_CONN_RESET_BY_OTHER_SIDE.
Note: Discovering a fatal error on the connection would trigger all event waits on this socket (sync_send(), sync_receive(), Event_set::sync_wait(), Event_set::async_wait()) to execute on-event behavior (return, return, return, invoke handler, respectively). Therefore this method will cause just that, if applicable.
Note: As a corollary, a socket closing this way (or any other way) does NOT cause that socket's events (if any) to be removed from any Event_set objects. Clearing an Event_set of all or some sockets is the Event_set user's responsibility (the classic way being Event_set::close()).
close_start()
and close_final()
, use of close_abruptly() should be discouraged, or it may even be deprecated (e.g., Node
s lack a way to initiate an abrupt close for a specific socket).bool
(false
on failure)?err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_NODE_NOT_RUNNING, or – if socket already closed (state() == State::S_CLOSED ) – then the error that caused the closure. |
Error_code flow::net_flow::Peer_socket::disconnect_cause | ( | ) | const |
The error code that perviously caused state() to become State::S_CLOSED, or success code if state is not CLOSED.
For example, error::code::S_CONN_RESET_BY_OTHER_SIDE (if was connected) or error::Code::S_CONN_TIMEOUT (if was connecting)
size_t flow::net_flow::Peer_socket::get_connect_metadata | ( | const boost::asio::mutable_buffer & | buffer, |
Error_code * | err_code = 0 |
||
) | const |
Obtains the serialized connect metadata, as supplied by the user during the connection handshake.
If this side initiated the connection (Node::connect() and friends), then this will equal what was passed to the connect_with_metadata() (or similar) method. More likely, if this side accepted the connection (Server_socket::accept() and friends), then this will equal what the user on the OTHER side passed to connect_with_metadata() or similar.
boost::endian::native_to_little()
(and similar) before connecting; and on the other side use the reverse (boost::endian::little_to_native()
) before using the value. Packet dumps will show a flipped (little-endian) representation, while with most platforms the conversion will be a no-op at compile time. Alternatively use native_to_big()
and vice-versa. _with_metadata
in the name was used, then the metadata are composed of a single byte with the zero value. buffer | A buffer to copy the metadata into. |
err_code | See flow::Error_code docs for error reporting semantics. |
Peer_socket_info flow::net_flow::Peer_socket::info | ( | ) | const |
Returns a structure containing the most up-to-date stats about this connection.
flow_port_t flow::net_flow::Peer_socket::local_port | ( | ) | const |
The local Flow-protocol port chosen by the Node (if active or passive open) or user (if passive open) for this side of the connection.
For a given Peer_socket, this will always return the same value, even if state is State::S_CLOSED. However, when state is State::S_CLOSED, the port may be unused or taken by another socket.
size_t flow::net_flow::Peer_socket::max_block_size | ( | ) | const |
The maximum number of bytes of user data per received or sent packet on this connection.
See Peer_socket_options::m_st_max_block_size. Note that this method is ESSENTIAL when using the socket in unreliable mode (assuming you want to implement reliability outside of net_flow
).
Node * flow::net_flow::Peer_socket::node | ( | ) | const |
Node that produced this Peer_socket.
Peer_socket_options flow::net_flow::Peer_socket::options | ( | ) | const |
Copies this socket's option set and returns that copy.
If you intend to use set_options() to modify a socket's options, we recommend you make the modifications on the copy returned by options().
size_t flow::net_flow::Peer_socket::receive | ( | const Mutable_buffer_sequence & | target, |
Error_code * | err_code = 0 |
||
) |
Receives (consumes from the Receive buffer) bytes of data, up to a given maximum cumulative number of bytes as inferred from size of provided target buffer sequence.
The data are copied into the user's structure and then removed from the Receive buffer.
The method does not block. In particular if there are no data already received from the other side, we return no data.
If the provided buffer has size zero, the method is a NOOP other than possibly logging.
These are the possible outcomes.
*err_code
is set to success unless null; no data returned.S_OPEN+S_CONNECTING
). Socket not Readable. 0 is returned; *err_code
is set to success unless null; no data returned.S_OPEN+S_CONNECTED
) or gracefully shutting down (S_OPEN+S_DISCONNECTING
). Socket Readable. >= 1 is returned; *err_code is set to success; data returned.*err_code
is set to the specific error; no data buffered. (If err_code
null, Runtime_error thrown.)The semantics of -3- (the success case) are as follows. N bytes will be copied from Receive buffer beginning at the start of the Mutable_buffer_sequence target
. These N bytes may be spread across 1 or more buffers in that sequence; the subdivision structure of the sequence of bytes into buffers has no effect on the bytes, or order thereof, that will be moved from the Receive buffer (e.g., target
could be N+ 1-byte buffers, or one N+-byte buffer – the popped Receive buffer would be the same, as would be the extracted bytes). N equals the smaller of: the available bytes in the Receive buffer; and buffer_size(target)
. We return N.
See the send() doc header.
Mutable_buffer_sequence | Type that models the boost.asio MutableBufferSequence concept (see Boost docs). Basically, it's any container with elements convertible to boost::asio::mutable_buffer ; and bidirectional iterator support. Examples: vector<mutable_buffer> , list<mutable_buffer> . Why allow mutable_buffer instead of, say, Sequence of bytes? Same reason as boost.asio's receive functions: it allows a great amount of flexibility without sacrificing performance, since boost::asio::buffer() function can adapt lots of different objects (arrays, vector s, string s, and more of bytes, integers, and more). |
target | Buffer sequence to which a stream of bytes to consume from Receive buffer will be written. |
err_code | See flow::Error_code docs for error reporting semantics. Error implies that neither this receive() nor any subsequent receive() on this socket will succeeed. (In particular a clean disconnect is an error.) |
target
). Always 0 if bool(*err_code) == true
when receive() returns. const Remote_endpoint & flow::net_flow::Peer_socket::remote_endpoint | ( | ) | const |
Intended other side of the connection (regardless of success, failure, or current State).
For a given Peer_socket, this will always return the same value, even if state is State::S_CLOSED.
size_t flow::net_flow::Peer_socket::send | ( | const Const_buffer_sequence & | data, |
Error_code * | err_code = 0 |
||
) |
Sends (adds to the Send buffer) the given bytes of data up to a maximum internal buffer size; and asynchronously sends them to the other side.
The data given is copied into *this
, in the order given. Only as many bytes as possible without the Send buffer size exceeding a certain max are copied.
The method does not block. Data are then sent asynchronously (in the background).
Method does nothing except possibly logging if there are no bytes in data.
These are the possible outcomes.
*err_code
is set to success unless null; no data buffered.S_OPEN+S_CONNECTING
state). Socket not Writable. 0 is returned; *err_code
is set to success unless null; no data buffered.S_OPEN+S_CONNECTED
). Socket Writable. >= 1 is returned; *err_code
is set to success; data buffered.*err_code
is set to the specific error unless null; no data buffered. (If err_code
null, Runtime_error thrown.)The semantics of -3- (the success case) are as follows. N bytes will be copied into Send buffer from the start of the Const_buffer_sequence data. These N bytes may be spread across 1 or more buffers in that sequence; the subdivision structure of the sequence of bytes into buffers has no effect on what will be buffered in Send buffer (e.g., "data" could be N+ 1-byte buffers, or one N+-byte buffer – the result would be the same). N equals the smaller of: the available space in the Send buffer; and buffer_size(data)
. We return N.
Reliability and ordering are guaranteed, and there is no notion of message boundaries. There is no possibility of data duplication. In other words full stream-of-bytes functionality is provided, as in TCP.
NO reliability guarantees are given, UNLESS ALL calls to send() (and other *send
() methods) satisfy the condition: 'buffer_size(data)
is a multiple of sock->max_block_size()
'; AND all calls to receive() (and other *receive()
methods) on the OTHER side satisfy the condition: 'buffer_size(target)
is a multiple of sock->max_block_size()
.' If and only if these guidelines are followed, and there is no connection closure, the following reliability guarantee is made:
Let a "block" be a contiguous chunk of bytes in a "data" buffer sequence immediately following another "block," except the first "block" in a connection, which begins with the first byte of the "data" buffer sequence passed to the first *send()
call on that connection. Then: Each given block will either be available to *receive()
on the other side exactly once and without corruption; or not available to *receive()
at all. Blocks may arrive in a different order than specified here, including with respect to other *send()
calls performed before or after this one. In other words, these are guaranteed: block boundary preservation, protection against corruption, protection again duplication. These are not guaranteed: order preservation, delivery. Informally, the latter factors are more likely to be present on higher quality network paths.
Const_buffer_sequence | Type that models the boost.asio ConstBufferSequence concept (see Boost docs). Basically, it's any container with elements convertible to boost::asio::const_buffer ; and bidirectional iterator support. Examples: vector<const_buffer> , list<const_buffer> . Why allow const_buffer instead of, say, Sequence of bytes? Same reason as boost.asio's send functions: it allows a great amount of flexibility without sacrificing performance, since boost::asio::buffer() function can adapt lots of different objects (arrays, vector s, string s, and more – composed of bytes, integers, and more). |
data | Buffer sequence from which a stream of bytes to add to Send buffer will be obtained. |
err_code | See flow::Error_code docs for error reporting semantics. Error implies that neither this send() nor any subsequent *send() on this socket will succeeed. (In particular a clean disconnect is an error.) |
bool(*err_code) == true
when send() returns. bool flow::net_flow::Peer_socket::set_options | ( | const Peer_socket_options & | opts, |
Error_code * | err_code = 0 |
||
) |
Dynamically replaces the current options set (options()) with the given options set.
Only those members of opts
designated as dynamic (as opposed to static) may be different between options() and opts
. If this is violated, it is an error, and no options are changed.
Typically one would acquire a copy of the existing options set via options(), modify the desired dynamic data members of that copy, and then apply that copy back by calling set_options().
opts | The new options to apply to this socket. It is copied; no reference is saved. |
err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_STATIC_OPTION_CHANGED, error::Code::S_OPTION_CHECK_FAILED, error::Code::S_NODE_NOT_RUNNING. |
true
on success, false
on error. Peer_socket::State flow::net_flow::Peer_socket::state | ( | Open_sub_state * | open_sub_state = 0 | ) | const |
Current State of the socket.
open_sub_state | Ignored if null. Otherwise, if and only if State::S_OPEN is returned, *open_sub_state is set to the current sub-state of S_OPEN . |
bool flow::net_flow::Peer_socket::sync_receive | ( | const boost::asio::null_buffers & | , |
const boost::chrono::duration< Rep, Period > & | max_wait, | ||
Error_code * | err_code = 0 |
||
) |
sync_receive()
operating in null_buffers
mode, wherein – if Readable state is reached – the actual data are not moved into any buffer, leaving that to the caller to do if desired.
Hence, this is a way of waiting for Readable state that could be more concise in some situations than Event_set::sync_wait().
These are the possible outcomes:
S_OPEN+S_CONNECTED
) or gracefully shutting down (S_OPEN+S_DISCONNECTING
). Socket Readable. true
is returned; *err_code
is set to success unless null.false
is returned; *err_code
is set to the specific error unless null. *err_code == S_WAIT_INTERRUPTED
means the wait was interrupted (similarly to POSIX's EINTR
). (If err_code
null, Runtime_error thrown.)Note that it is NOT possible to return false
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 other sync_receive(). |
Period | See other sync_receive(). |
max_wait | See other sync_receive(). |
err_code | See flow::Error_code docs for error reporting semantics. Error, except WAIT_INTERRUPTED or WAIT_USER_TIMEOUT , implies that neither this nor any subsequent receive() on this socket will succeeed. (In particular a clean disconnect is an error.) |
true
if there are 1+ bytes ready to read; false
if either a timeout has occurred (no bytes ready), or another error has occurred. bool flow::net_flow::Peer_socket::sync_receive | ( | const boost::asio::null_buffers & | tag, |
Error_code * | err_code = 0 |
||
) |
Equivalent to sync_receive(null_buffers(), duration::max(), err_code)
; i.e., sync_receive(null_buffers)
with no timeout.
err_code | See other sync_receive(). |
tag | Tag argument. |
size_t flow::net_flow::Peer_socket::sync_receive | ( | const Mutable_buffer_sequence & | target, |
const boost::chrono::duration< Rep, Period > & | max_wait, | ||
Error_code * | err_code = 0 |
||
) |
Blocking (synchronous) version of receive().
Acts just like receive(), except that if socket is not immediately Readable (i.e., receive() would return 0 and no error), waits until it is Readable (receive() would return either >0, or 0 and an error) and returns receive(target, err_code)
. If a timeout is specified, and this timeout expires before socket is Readable, it acts as if receive() produced error::Code::S_WAIT_USER_TIMEOUT.
These are the possible outcomes:
S_OPEN+S_CONNECTED
) or gracefully shutting down (S_OPEN+S_DISCONNECTING
). Socket Readable. >= 1 is returned; *err_code
is set to success unless null; data returned.*err_code
is set to the specific error unless null; no data buffered. *err_code == S_WAIT_INTERRUPTED
means the wait was interrupted (similarly to POSIX's EINTR
). (If err_code
null, Runtime_error thrown.)The semantics of -1- (the success case) equal those of receive().
Note that it is NOT possible to return 0 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). |
Mutable_buffer_sequence | See receive(). |
target | See receive(). |
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). |
err_code | See flow::Error_code docs for error reporting semantics. Error, except WAIT_INTERRUPTED or WAIT_USER_TIMEOUT , implies that neither this receive() nor any subsequent receive() on this socket will succeeed. (In particular a clean disconnect is an error.) |
bool(*err_code) == true
when sync_receive() returns. size_t flow::net_flow::Peer_socket::sync_receive | ( | const Mutable_buffer_sequence & | target, |
Error_code * | err_code = 0 |
||
) |
Equivalent to sync_receive(target, duration::max(), err_code)
; i.e., sync_receive() with no timeout.
Mutable_buffer_sequence | See other sync_receive(). |
target | See other sync_receive(). |
err_code | See other sync_receive(). |
bool flow::net_flow::Peer_socket::sync_send | ( | const boost::asio::null_buffers & | , |
const boost::chrono::duration< Rep, Period > & | max_wait, | ||
Error_code * | err_code = 0 |
||
) |
sync_send()
operating in null_buffers
mode, wherein – if Writable state is reached – the actual data are not moved out of any buffer, leaving that to the caller to do if desired.
Hence, this is a way of waiting for Writable state that could be more concise in some situations than Event_set::sync_wait().
These are the possible outcomes:
S_OPEN+S_CONNECTED
). Socket Writable. true
is returned; *err_code
is set to success unless null.false
is returned; *err_code
is set to the specific error unless null. *err_code == S_WAIT_INTERRUPTED
means the wait was interrupted (similarly to POSIX's EINTR
). (If err_code
null, Runtime_error thrown.)Note that it is NOT possible to return false
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 other sync_send(). |
Period | See other sync_send(). |
max_wait | See other sync_receive(). |
err_code | See flow::Error_code docs for error reporting semantics. Error, except WAIT_INTERRUPTED or WAIT_USER_TIMEOUT , implies that neither this nor any subsequent send() on this socket will succeeed. (In particular a clean disconnect is an error.) |
true
if 1+ bytes are possible to add to Send buffer; false
if either a timeout has occurred (bytes not writable), or another error has occurred. bool flow::net_flow::Peer_socket::sync_send | ( | const boost::asio::null_buffers & | tag, |
Error_code * | err_code = 0 |
||
) |
Equivalent to sync_send(null_buffers(), duration::max(), err_code)
; i.e., sync_send(null_buffers)
with no timeout.
err_code | See other sync_receive(). |
tag | Tag argument. |
size_t flow::net_flow::Peer_socket::sync_send | ( | const Const_buffer_sequence & | data, |
const boost::chrono::duration< Rep, Period > & | max_wait, | ||
Error_code * | err_code = 0 |
||
) |
Blocking (synchronous) version of send().
Acts just like send(), except that if Socket is not immediately Writable (i.e., send() would return 0 and no error), waits until it is Writable (send() would return either >0, or 0 and an error) and returns send(data, err_code)
. If a timeout is specified, and this timeout expires before socket is Writable, acts like send() executed on an un-Writable socket.
These are the possible outcomes (assuming there are data in the argument data
).
S_OPEN+S_CONNECTED
). Socket Writable. >= 1 is returned; *err_code
is set to success unless null; data buffered.*err_code
is set to the specific error unless null; no data buffered. (If err_code
null, Runtime_error thrown.) The code error::Code::S_WAIT_INTERRUPTED means the wait was interrupted (similarly to POSIX's EINTR
).The semantics of -1- (the success case) equal those of send().
Note that it is NOT possible to return 0 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). |
Const_buffer_sequence | See send(). |
data | See send(). |
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). |
err_code | See flow::Error_code docs for error reporting semantics. Error, except WAIT_INTERRUPTED or WAIT_USER_TIMEOUT , implies that neither this send() nor any subsequent send() on this socket will succeeed. (In particular a clean disconnect is an error.) |
bool(*err_code) == true
when sync_send() returns. size_t flow::net_flow::Peer_socket::sync_send | ( | const Const_buffer_sequence & | data, |
Error_code * | err_code = 0 |
||
) |
Equivalent to sync_send(data, duration::max(), err_code)
; i.e., sync_send() with no timeout.
Const_buffer_sequence | See other sync_send(). |
data | See other sync_send(). |
err_code | See other sync_send(). |
|
related |
Prints string representation of given socket to given standard ostream
and returns the latter.
The representation includes the local and remote endpoints 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. |
sock | Object to serialize. May be null. |
os
.