21#include <flow/common.hpp> 
   22#include <boost/array.hpp> 
   25static_assert(
false, 
"Should not have gotten to this line; should have required Linux; this .cpp file assumes it.  " 
   26                       "Might work in other POSIX OS (e.g., macOS) but must be checked/tested.");
 
   29#include <sys/socket.h> 
   41  using boost::system::system_category;
 
   43  namespace sys_err_codes = boost::system::errc;
 
   55                                     logger_ptr, peer_socket_ptr, payload_hndl, payload_blob, _1);
 
   62  assert(peer_socket_ptr);
 
   63  auto& peer_socket = *peer_socket_ptr;
 
   65  FLOW_LOG_SET_CONTEXT(logger_ptr, Log_component::S_TRANSPORT);
 
   66  FLOW_LOG_TRACE(
"Connected local peer socket wants to write from location @ [" << payload_blob.data() << 
"] " 
   67                 "plus native handle [" << payload_hndl << 
"].  Will try to send.");
 
   83  iovec native_buf1 = { 
const_cast<void*
>(payload_blob.data()), payload_blob.size() };
 
  108  constexpr size_t N_PAYLOAD_FDS = 1;
 
  131  } msg_control_as_union;
 
  133  sendmsg_hdr.msg_control = msg_control_as_union.m_buf.c_array();
 
  134  sendmsg_hdr.msg_controllen = 
sizeof(msg_control_as_union.m_buf);
 
  135  cmsghdr* 
const sendmsg_hdr_cmsg_ptr = CMSG_FIRSTHDR(&sendmsg_hdr); 
 
  136  sendmsg_hdr_cmsg_ptr->cmsg_level = SOL_SOCKET;
 
  137  sendmsg_hdr_cmsg_ptr->cmsg_type = SCM_RIGHTS;
 
  141  static_assert(N_PAYLOAD_FDS == 1, 
"Should be only passing one native handle into sendmsg() as of this writing.");
 
  144  const auto n_sent_or_error
 
  145    = sendmsg(peer_socket.native_handle(), &sendmsg_hdr,
 
  151              MSG_DONTWAIT | MSG_NOSIGNAL);
 
  154  if (n_sent_or_error == -1)
 
  161    const Error_code sys_err_code(errno, system_category());
 
  162    if ((sys_err_code == sys_err_codes::operation_would_block) || 
 
  163        (sys_err_code == sys_err_codes::resource_unavailable_try_again)) 
 
  165      FLOW_LOG_TRACE(
"Write attempt indicated would-block; not an error condition.  Nothing sent.");
 
  176      *err_code = boost::asio::error::would_block;
 
  181    assert(sys_err_code);
 
  184    FLOW_ERROR_SYS_ERROR_LOG_WARNING(); 
 
  185    FLOW_LOG_WARNING(
"Connected local peer socket tried to write from " 
  186                     "location @ [" << payload_blob.data() << 
"] plus native handle [" << payload_hndl << 
"]; " 
  187                     "but an unrecoverable error occurred.  Nothing sent.");
 
  188    *err_code = sys_err_code;
 
  193  assert (n_sent_or_error > 0);
 
  195  FLOW_LOG_TRACE(
"sendmsg() reports the native handle [" << payload_hndl << 
"] was successfully sent; as " 
  196                 "were [" << n_sent_or_error << 
"] of the blob's [" << payload_blob.size() << 
"] bytes.");
 
  198  return n_sent_or_error;
 
  208  using boost::system::system_category;
 
  210  namespace sys_err_codes = boost::system::errc;
 
  217  using ::MSG_DONTWAIT;
 
  222                                     logger_ptr, peer_socket_ptr, target_payload_hndl_ptr,
 
  223                                     target_payload_blob, _1, message_flags);
 
  230  assert(peer_socket_ptr);
 
  231  assert(target_payload_hndl_ptr);
 
  233  auto& peer_socket = *peer_socket_ptr;
 
  234  auto& target_payload_hndl = *target_payload_hndl_ptr;
 
  236  FLOW_LOG_SET_CONTEXT(logger_ptr, Log_component::S_TRANSPORT);
 
  237  FLOW_LOG_TRACE(
"Connected local peer socket wants to read up to [" << target_payload_blob.size() << 
"] bytes " 
  238                 "to location @ [" << target_payload_blob.data() << 
"] " 
  239                 "plus possibly a native handle.  Will try to receive.");
 
  241  assert(target_payload_hndl.null()); 
 
  251  iovec native_buf1 = { target_payload_blob.data(), target_payload_blob.size() };
 
  267  recvmsg_hdr.msg_flags = 0;
 
  275  constexpr size_t N_PAYLOAD_FDS = 1;
 
  281  } msg_control_as_union;
 
  283  msg_control_as_union.m_buf.fill(0);
 
  285  recvmsg_hdr.msg_control = msg_control_as_union.m_buf.c_array();
 
  286  recvmsg_hdr.msg_controllen = 
sizeof(msg_control_as_union.m_buf);
 
  288  const auto n_rcvd_or_error
 
  289    = recvmsg(peer_socket.native_handle(), &recvmsg_hdr,
 
  292              MSG_DONTWAIT | message_flags); 
 
  296  if (n_rcvd_or_error == -1)
 
  301    const Error_code sys_err_code(errno, system_category());
 
  302    if ((sys_err_code == sys_err_codes::operation_would_block) || 
 
  303        (sys_err_code == sys_err_codes::resource_unavailable_try_again)) 
 
  307      FLOW_LOG_TRACE(
"Read attempt indicated would-block; not an error condition.  Nothing received.");
 
  309      *err_code = boost::asio::error::would_block;
 
  314    assert(sys_err_code);
 
  317    FLOW_ERROR_SYS_ERROR_LOG_WARNING(); 
 
  318    FLOW_LOG_WARNING(
"Connected local peer socket tried to read up to [" << target_payload_blob.size() << 
"] bytes at " 
  319                     "location @ [" << target_payload_blob.data() << 
"] plus possibly a native handle; " 
  320                     "but an unrecoverable error occurred.  Nothing received.");
 
  321    *err_code = sys_err_code;
 
  326  if (n_rcvd_or_error == 0)
 
  331    FLOW_LOG_TRACE(
"Connected local peer socket tried to read up to [" << target_payload_blob.size() << 
"] bytes at " 
  332                   "location @ [" << target_payload_blob.data() << 
"] plus possibly a native handle; " 
  333                   "but it returned EOF meaning orderly connection shutdown by peer.  Nothing received.");
 
  334    *err_code = boost::asio::error::eof;
 
  338  assert(n_rcvd_or_error > 0);
 
  343  if (recvmsg_hdr.msg_flags != 0)
 
  345    FLOW_LOG_INFO(
"Connected local peer socket tried to read up to [" << target_payload_blob.size() << 
"] bytes at " 
  346                  "location @ [" << target_payload_blob.data() << 
"] plus possibly a native handle; " 
  347                  "and it returned it read [" << n_rcvd_or_error << 
"] bytes successfully but also returned raw " 
  348                  "out-flags value [0x" << std::hex << recvmsg_hdr.msg_flags << std::dec << 
"].  " 
  349                  "Will check for relevant flags but otherwise " 
  350                  "ignoring if nothing bad.  Logging at elevated level because it's interesting; please investigate.");
 
  352    if ((recvmsg_hdr.msg_flags & MSG_CTRUNC) != 0)
 
  354      FLOW_LOG_WARNING(
"Connected local peer socket tried to read up to [" << target_payload_blob.size() << 
"] bytes " 
  355                       "at location @ [" << target_payload_blob.data() << 
"] plus possibly a native handle; " 
  356                       "and it returned it read [" << n_rcvd_or_error << 
"] bytes successfully but also returned raw " 
  357                       "out-flags value [0x" << recvmsg_hdr.msg_flags << 
"] which includes MSG_CTRUNC.  " 
  358                       "That flag indicates more stuff was sent as ancillary data; but we expect at most 1 native " 
  359                       "handle.  Other side sent something strange.  Acting as if nothing received + error.");
 
  368  cmsghdr* 
const recvmsg_hdr_cmsg_ptr = CMSG_FIRSTHDR(&recvmsg_hdr);
 
  369  if (recvmsg_hdr_cmsg_ptr)
 
  372    if ((recvmsg_hdr_cmsg_ptr->cmsg_level == SOL_SOCKET) &&
 
  373        (recvmsg_hdr_cmsg_ptr->cmsg_type == SCM_RIGHTS))
 
  375      static_assert(N_PAYLOAD_FDS == 1, 
"Should be only dealing with one native handle with recvmsg() " 
  376                                        "as of this writing.");
 
  377      target_payload_hndl.m_native_handle
 
  382      FLOW_LOG_WARNING(
"Connected local peer socket tried to read up to [" << target_payload_blob.size() << 
"] bytes " 
  383                       "at location @ [" << target_payload_blob.data() << 
"] plus possibly a native handle; " 
  384                       "and it returned it read [" << n_rcvd_or_error << 
"] bytes successfully but also " 
  385                       "unexpected ancillary data of csmg_level|cmsg_type " 
  386                       "[" << recvmsg_hdr_cmsg_ptr->cmsg_level << 
'|' << recvmsg_hdr_cmsg_ptr->cmsg_type << 
"].  " 
  387                       "Acting as if nothing received + error.");
 
  392    if (CMSG_NXTHDR(&recvmsg_hdr, recvmsg_hdr_cmsg_ptr))
 
  396      FLOW_LOG_WARNING(
"Connected local peer socket tried to read up to [" << target_payload_blob.size() << 
"] bytes " 
  397                       "at location @ [" << target_payload_blob.data() << 
"] plus possibly a native handle; " 
  398                       "and it returned it read [" << n_rcvd_or_error << 
"] bytes and native handle " 
  399                       "[" << target_payload_hndl << 
"] but also more ancillary data; but we expect at most 1 native " 
  400                       "handle.  Other side sent something strange.  Acting as if nothing received + error.");
 
  409  FLOW_LOG_TRACE(
"recvmsg() reports receipt of possible native handle [" << target_payload_hndl << 
"]; as well as " 
  410                 "[" << n_rcvd_or_error << 
"] of the blob's [" << target_payload_blob.size() << 
"]-byte capacity.");
 
  412  return n_rcvd_or_error;
 
  417  using flow::util::Task_engine;
 
  420  if (peer_socket_native_or_null.null())
 
  429  Task_engine task_engine;
 
  430  [[maybe_unused]] 
Peer_socket sock(task_engine, 
Protocol(), peer_socket_native_or_null.m_native_handle);
 
Opt_peer_process_credentials()
Default ctor: each value is initialized to zero or equivalent.
Opt_peer_process_credentials & operator=(const Opt_peer_process_credentials &src)
Boring copy assignment.
Additional (versus boost.asio) APIs for advanced work with local stream (Unix domain) sockets includi...
local_ns::stream_protocol Protocol
Short-hand for boost.asio Unix domain stream-socket protocol.
size_t nb_write_some_with_native_handle(flow::log::Logger *logger_ptr, Peer_socket *peer_socket_ptr, Native_handle payload_hndl, const util::Blob_const &payload_blob, Error_code *err_code)
boost.asio extension similar to peer_socket->non_blocking(true); auto n = peer_socket->write_some(pay...
Protocol::socket Peer_socket
Short-hand for boost.asio Unix domain peer stream-socket (usually-connected-or-empty guy).
size_t nb_read_some_with_native_handle(flow::log::Logger *logger_ptr, Peer_socket *peer_socket_ptr, Native_handle *target_payload_hndl_ptr, const util::Blob_mutable &target_payload_blob, Error_code *err_code, int message_flags)
boost.asio extension similar to peer_socket->non_blocking(true); auto n = peer_socket->read_some(targ...
void release_native_peer_socket(Native_handle &&peer_socket_native_or_null)
Little utility that returns the raw Native_handle suitable for Peer_socket to the OS.
@ S_LOW_LVL_UNEXPECTED_STREAM_PAYLOAD_BEYOND_HNDL
Unable to receive incoming traffic: message contains more than: 1 blob plus 0-1 native handles.
util::Native_handle Native_handle
Convenience alias for the commonly used type util::Native_handle.
boost::asio::mutable_buffer Blob_mutable
Short-hand for an mutable blob somewhere in memory, stored as exactly a void* and a size_t.
boost::asio::const_buffer Blob_const
Short-hand for an immutable blob somewhere in memory, stored as exactly a void const * and a size_t.
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
A monolayer-thin wrapper around a native handle, a/k/a descriptor a/k/a FD.
int handle_t
The native handle type. Much logic relies on this type being light-weight (fast to copy).
handle_t m_native_handle
The native handle (possibly equal to S_NULL_HANDLE), the exact payload of this Native_handle.