21#include <flow/common.hpp>
22#include <boost/array.hpp>
25# error "Should not have gotten to this line; should have required Linux; this .cpp file assumes it."
28#include <sys/socket.h>
40 namespace bind_ns = flow::util::bind_ns;
41 using boost::system::system_category;
43 namespace sys_err_codes = boost::system::errc;
55 logger_ptr, peer_socket_ptr, payload_hndl, bind_ns::cref(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 namespace bind_ns = flow::util::bind_ns;
209 using boost::system::system_category;
211 namespace sys_err_codes = boost::system::errc;
218 using ::MSG_DONTWAIT;
223 logger_ptr, peer_socket_ptr, target_payload_hndl_ptr,
224 bind_ns::cref(target_payload_blob), _1, message_flags);
231 assert(peer_socket_ptr);
232 assert(target_payload_hndl_ptr);
234 auto& peer_socket = *peer_socket_ptr;
235 auto& target_payload_hndl = *target_payload_hndl_ptr;
237 FLOW_LOG_SET_CONTEXT(logger_ptr, Log_component::S_TRANSPORT);
238 FLOW_LOG_TRACE(
"Connected local peer socket wants to read up to [" << target_payload_blob.size() <<
"] bytes "
239 "to location @ [" << target_payload_blob.data() <<
"] "
240 "plus possibly a native handle. Will try to receive.");
242 assert(target_payload_hndl.null());
252 iovec native_buf1 = { target_payload_blob.data(), target_payload_blob.size() };
268 recvmsg_hdr.msg_flags = 0;
276 constexpr size_t N_PAYLOAD_FDS = 1;
282 } msg_control_as_union;
284 msg_control_as_union.m_buf.fill(0);
286 recvmsg_hdr.msg_control = msg_control_as_union.m_buf.c_array();
287 recvmsg_hdr.msg_controllen =
sizeof(msg_control_as_union.m_buf);
289 const auto n_rcvd_or_error
290 = recvmsg(peer_socket.native_handle(), &recvmsg_hdr,
293 MSG_DONTWAIT | message_flags);
297 if (n_rcvd_or_error == -1)
302 const Error_code sys_err_code(errno, system_category());
303 if ((sys_err_code == sys_err_codes::operation_would_block) ||
304 (sys_err_code == sys_err_codes::resource_unavailable_try_again))
308 FLOW_LOG_TRACE(
"Read attempt indicated would-block; not an error condition. Nothing received.");
310 *err_code = boost::asio::error::would_block;
315 assert(sys_err_code);
318 FLOW_ERROR_SYS_ERROR_LOG_WARNING();
319 FLOW_LOG_WARNING(
"Connected local peer socket tried to read up to [" << target_payload_blob.size() <<
"] bytes at "
320 "location @ [" << target_payload_blob.data() <<
"] plus possibly a native handle; "
321 "but an unrecoverable error occurred. Nothing received.");
322 *err_code = sys_err_code;
327 if (n_rcvd_or_error == 0)
332 FLOW_LOG_TRACE(
"Connected local peer socket tried to read up to [" << target_payload_blob.size() <<
"] bytes at "
333 "location @ [" << target_payload_blob.data() <<
"] plus possibly a native handle; "
334 "but it returned EOF meaning orderly connection shutdown by peer. Nothing received.");
335 *err_code = boost::asio::error::eof;
339 assert(n_rcvd_or_error > 0);
344 if (recvmsg_hdr.msg_flags != 0)
346 FLOW_LOG_INFO(
"Connected local peer socket tried to read up to [" << target_payload_blob.size() <<
"] bytes at "
347 "location @ [" << target_payload_blob.data() <<
"] plus possibly a native handle; "
348 "and it returned it read [" << n_rcvd_or_error <<
"] bytes successfully but also returned raw "
349 "out-flags value [0x" << std::hex << recvmsg_hdr.msg_flags << std::dec <<
"]. "
350 "Will check for relevant flags but otherwise "
351 "ignoring if nothing bad. Logging at elevated level because it's interesting; please investigate.");
353 if ((recvmsg_hdr.msg_flags & MSG_CTRUNC) != 0)
355 FLOW_LOG_WARNING(
"Connected local peer socket tried to read up to [" << target_payload_blob.size() <<
"] bytes "
356 "at location @ [" << target_payload_blob.data() <<
"] plus possibly a native handle; "
357 "and it returned it read [" << n_rcvd_or_error <<
"] bytes successfully but also returned raw "
358 "out-flags value [0x" << recvmsg_hdr.msg_flags <<
"] which includes MSG_CTRUNC. "
359 "That flag indicates more stuff was sent as ancillary data; but we expect at most 1 native "
360 "handle. Other side sent something strange. Acting as if nothing received + error.");
369 cmsghdr*
const recvmsg_hdr_cmsg_ptr = CMSG_FIRSTHDR(&recvmsg_hdr);
370 if (recvmsg_hdr_cmsg_ptr)
373 if ((recvmsg_hdr_cmsg_ptr->cmsg_level == SOL_SOCKET) &&
374 (recvmsg_hdr_cmsg_ptr->cmsg_type == SCM_RIGHTS))
376 static_assert(N_PAYLOAD_FDS == 1,
"Should be only dealing with one native handle with recvmsg() "
377 "as of this writing.");
378 target_payload_hndl.m_native_handle
383 FLOW_LOG_WARNING(
"Connected local peer socket tried to read up to [" << target_payload_blob.size() <<
"] bytes "
384 "at location @ [" << target_payload_blob.data() <<
"] plus possibly a native handle; "
385 "and it returned it read [" << n_rcvd_or_error <<
"] bytes successfully but also "
386 "unexpected ancillary data of csmg_level|cmsg_type "
387 "[" << recvmsg_hdr_cmsg_ptr->cmsg_level <<
'|' << recvmsg_hdr_cmsg_ptr->cmsg_type <<
"]. "
388 "Acting as if nothing received + error.");
393 if (CMSG_NXTHDR(&recvmsg_hdr, recvmsg_hdr_cmsg_ptr))
397 FLOW_LOG_WARNING(
"Connected local peer socket tried to read up to [" << target_payload_blob.size() <<
"] bytes "
398 "at location @ [" << target_payload_blob.data() <<
"] plus possibly a native handle; "
399 "and it returned it read [" << n_rcvd_or_error <<
"] bytes and native handle "
400 "[" << target_payload_hndl <<
"] but also more ancillary data; but we expect at most 1 native "
401 "handle. Other side sent something strange. Acting as if nothing received + error.");
410 FLOW_LOG_TRACE(
"recvmsg() reports receipt of possible native handle [" << target_payload_hndl <<
"]; as well as "
411 "[" << n_rcvd_or_error <<
"] of the blob's [" << target_payload_blob.size() <<
"]-byte capacity.");
413 return n_rcvd_or_error;
418 using flow::util::Task_engine;
421 if (peer_socket_native_or_null.null())
430 Task_engine task_engine;
431 [[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.