31#include <sys/socket.h>
38 template <
typename Tin,
typename Tout,
typename Fn1,
typename Fn2>
39 std::size_t copy( Tin in , Tout out , Fn1 fn_convert , Fn2 fn_empty )
41 return std::distance( out.begin() ,
42 std::remove_if( out.begin() , std::transform( in.begin() , in.end() , out.begin() , fn_convert ) , fn_empty ) ) ;
44 ssize_t sendmsg(
int fd ,
const iovec * , std::size_t ,
int flags ,
45 const sockaddr * address_p , socklen_t address_n ,
int fd_to_send ) noexcept ;
49ssize_t
G::Msg::send(
int fd ,
const void * buffer , std::size_t size ,
int flags )
noexcept
51 return sendto( fd , buffer , size , flags ,
nullptr , 0U ) ;
54ssize_t
G::Msg::sendto(
int fd ,
const void * buffer , std::size_t size ,
int flags ,
55 const sockaddr * address_p , socklen_t address_n )
noexcept
57 return ::sendto( fd , buffer , size , flags|MSG_NOSIGNAL ,
58 const_cast<sockaddr*
>(address_p) , address_n ) ;
61ssize_t
G::Msg::sendto(
int fd ,
const std::vector<std::string_view> & data ,
int flags ,
62 const sockaddr * address_p , socklen_t address_n )
68 else if( data.size() == 1U )
70 return sendto( fd , data[0].data() , data[0].size() , flags , address_p , address_n ) ;
74 std::array<::iovec,40> iovec_array ;
75 auto fn_convert = [](std::string_view sv){ ::iovec i; i.iov_len=sv.size(); i.iov_base=sv.empty()?
nullptr:
const_cast<char*
>(sv.data());
return i; } ;
76 auto fn_empty = [](const ::iovec &i){
return i.iov_base ==
nullptr; } ;
77 if( data.size() <= iovec_array.size() )
79 std::size_t n = MsgImp::copy( data , iovec_array , fn_convert , fn_empty ) ;
80 return n ? MsgImp::sendmsg( fd , iovec_array.data() , n , flags , address_p , address_n , -1 ) : 0U ;
84 std::vector<::iovec> iovec_vector( data.size() ) ;
85 std::size_t n = MsgImp::copy( data , iovec_vector , fn_convert , fn_empty ) ;
86 return n ? MsgImp::sendmsg( fd , iovec_vector.data() , n , flags , address_p , address_n , -1 ) : 0U ;
92ssize_t
G::Msg::sendto(
int fd ,
const void * buffer , std::size_t size ,
int flags ,
93 const sockaddr * address_p , socklen_t address_n ,
int fd_to_send )
95 if( fd_to_send == -1 )
97 return sendto( fd , buffer , size , flags , address_p , address_n ) ;
101 struct ::iovec io {} ;
102 io.iov_base =
const_cast<void*
>(buffer) ;
104 return MsgImp::sendmsg( fd , &io , 1U , flags , address_p , address_n , fd_to_send ) ;
109ssize_t G::MsgImp::sendmsg(
int fd , const ::iovec * iovec_p , std::size_t iovec_n ,
int flags ,
110 const sockaddr * address_p , socklen_t address_n ,
int fd_to_send )
noexcept
112 struct ::msghdr msg {} ;
114 msg.msg_name =
const_cast<sockaddr*
>(address_p) ;
115 msg.msg_namelen = address_n ;
116 msg.msg_iov =
const_cast<::iovec*
>(iovec_p) ;
117 msg.msg_iovlen = iovec_n ;
121 constexpr std::size_t space = CMSG_SPACE(
sizeof(
int) ) ;
122 static_assert( space != 0U ,
"" ) ;
123 std::array<char,space> control_buffer {} ;
124 std::memset( control_buffer.data() , 0 , control_buffer.size() ) ;
125 msg.msg_control = control_buffer.data() ;
126 msg.msg_controllen = control_buffer.size() ;
128 struct ::cmsghdr * cmsg = CMSG_FIRSTHDR( &msg ) ;
129 G_ASSERT( cmsg !=
nullptr ) ;
130 if( cmsg !=
nullptr )
132 cmsg->cmsg_len = CMSG_LEN(
sizeof(
int) ) ;
133 cmsg->cmsg_level = SOL_SOCKET ;
134 cmsg->cmsg_type = SCM_RIGHTS ;
135 std::memcpy( CMSG_DATA(cmsg) , &fd_to_send ,
sizeof(
int) ) ;
138 return ::sendmsg( fd , &msg , flags | MSG_NOSIGNAL ) ;
141ssize_t
G::Msg::recv(
int fd ,
void * buffer , std::size_t size ,
int flags )
noexcept
143 return ::recv( fd , buffer , size , flags ) ;
146ssize_t
G::Msg::recvfrom(
int fd ,
void * buffer , std::size_t size ,
int flags ,
147 sockaddr * address_p , socklen_t * address_np )
noexcept
149 return ::recvfrom( fd , buffer , size , flags , address_p , address_np ) ;
154 sockaddr * address_p , socklen_t * address_np ,
int * fd_received_p )
156 if( fd_received_p ==
nullptr )
157 return recvfrom( fd , buffer , size , flags , address_p , address_np ) ;
159 struct ::msghdr msg {} ;
161 msg.msg_name = address_p ;
162 msg.msg_namelen = address_np ==
nullptr ? socklen_t(0) : *address_np ;
164 struct ::iovec io {} ;
165 io.iov_base = buffer ;
170 std::array<char,CMSG_SPACE(
sizeof(
int))> control_buffer {} ;
171 msg.msg_control = control_buffer.data() ;
172 msg.msg_controllen = control_buffer.size() ;
174 ssize_t rc = ::recvmsg( fd , &msg , flags ) ;
176 if( rc >= 0 && msg.msg_controllen > 0U && fd_received_p !=
nullptr )
178 struct cmsghdr * cmsg = CMSG_FIRSTHDR( &msg ) ;
179 if( cmsg !=
nullptr && cmsg->cmsg_type == SCM_RIGHTS )
181 std::memcpy( fd_received_p , CMSG_DATA(cmsg) ,
sizeof(
int) ) ;
184 if( rc >= 0 && address_np !=
nullptr )
186 *address_np = msg.msg_namelen ;
static ssize_t recv(SOCKET, void *, std::size_t, int flags) noexcept
A recv() wrapper.
static bool fatal(int error) noexcept
Returns true if the error value indicates a permanent problem with the socket.
static ssize_t send(SOCKET, const void *, std::size_t, int flags) noexcept
A send() wrapper.
static ssize_t sendto(SOCKET, const void *, std::size_t, int flags, const sockaddr *, socklen_t) noexcept
A sendto() wrapper.
static ssize_t recvfrom(SOCKET, void *, std::size_t, int, sockaddr *, socklen_t *) noexcept
A recvfrom() wrapper.
static int errno_(const SignalSafe &=G::SignalSafe()) noexcept
Returns the process's current 'errno' value.
An empty structure that is used to indicate a signal-safe, reentrant implementation.