31#include <sys/socket.h>
38 template <
typename Tin,
typename Tout,
typename Fn1,
typename Fn2>
39 std::size_t copy( Tin , Tin , Tout , Tout , Fn1 fn_convert , Fn2 fn_empty ) ;
40 ssize_t sendmsg(
int fd ,
const iovec * , std::size_t ,
int flags ,
41 const sockaddr * address_p , socklen_t address_n ,
int fd_to_send ) noexcept ;
45ssize_t
G::Msg::send(
int fd ,
const void * buffer , std::size_t size ,
int flags )
noexcept
47 return sendto( fd , buffer , size , flags ,
nullptr , 0U ) ;
50ssize_t
G::Msg::sendto(
int fd ,
const void * buffer , std::size_t size ,
int flags ,
51 const sockaddr * address_p , socklen_t address_n )
noexcept
53 return ::sendto( fd , buffer , size , flags|MSG_NOSIGNAL ,
54 const_cast<sockaddr*
>(address_p) , address_n ) ;
57ssize_t
G::Msg::sendto(
int fd ,
const std::vector<string_view> & data ,
int flags ,
58 const sockaddr * address_p , socklen_t address_n )
64 else if( data.size() == 1U )
66 return sendto( fd , data[0].data() , data[0].size() , flags , address_p , address_n ) ;
70 #if GCONFIG_HAVE_IOVEC_SIMPLE
72 const ::iovec * io_p =
reinterpret_cast<const ::iovec*
>( &data[0] ) ;
73 return MsgImp::sendmsg( fd , io_p , data.size() , flags , address_p , address_n , -1 ) ;
75 std::array<::iovec,40> iovec_array ;
76 auto fn_convert = [](
string_view sv){ ::iovec i; i.iov_len=sv.size(); i.iov_base=sv.empty()?
nullptr:
const_cast<char*
>(sv.data());
return i; } ;
77 auto fn_empty = [](const ::iovec &i){
return i.iov_base ==
nullptr; } ;
78 if( data.size() <= iovec_array.size() )
80 std::size_t n = MsgImp::copy( data.begin() , data.end() , iovec_array.begin() , iovec_array.end() , fn_convert , fn_empty ) ;
81 return n ? MsgImp::sendmsg( fd , &iovec_array[0] , n , flags , address_p , address_n , -1 ) : 0U ;
85 std::vector<::iovec> iovec_vector( data.size() ) ;
86 std::size_t n = MsgImp::copy( data.begin() , data.end() , iovec_vector.begin() , iovec_vector.end() , fn_convert , fn_empty ) ;
87 return n ? MsgImp::sendmsg( fd , &iovec_vector[0] , n , flags , address_p , address_n , -1 ) : 0U ;
94ssize_t
G::Msg::sendto(
int fd ,
const void * buffer , std::size_t size ,
int flags ,
95 const sockaddr * address_p , socklen_t address_n ,
int fd_to_send )
97 if( fd_to_send == -1 )
99 return sendto( fd , buffer , size , flags , address_p , address_n ) ;
103 struct ::iovec io {} ;
104 io.iov_base =
const_cast<void*
>(buffer) ;
106 return MsgImp::sendmsg( fd , &io , 1U , flags , address_p , address_n , fd_to_send ) ;
111ssize_t G::MsgImp::sendmsg(
int fd , const ::iovec * iovec_p , std::size_t iovec_n ,
int flags ,
112 const sockaddr * address_p , socklen_t address_n ,
int fd_to_send )
noexcept
114 struct ::msghdr msg {} ;
116 msg.msg_name =
const_cast<sockaddr*
>(address_p) ;
117 msg.msg_namelen = address_n ;
118 msg.msg_iov =
const_cast<::iovec*
>(iovec_p) ;
119 msg.msg_iovlen = iovec_n ;
123 constexpr std::size_t space = CMSG_SPACE(
sizeof(
int) ) ;
124 static_assert( space != 0U ,
"" ) ;
125 std::array<char,space> control_buffer {} ;
126 std::memset( &control_buffer[0] , 0 , control_buffer.size() ) ;
127 msg.msg_control = &control_buffer[0] ;
128 msg.msg_controllen = control_buffer.size() ;
130 struct ::cmsghdr * cmsg = CMSG_FIRSTHDR( &msg ) ;
131 G_ASSERT( cmsg !=
nullptr ) ;
132 if( cmsg !=
nullptr )
134 cmsg->cmsg_len = CMSG_LEN(
sizeof(
int) ) ;
135 cmsg->cmsg_level = SOL_SOCKET ;
136 cmsg->cmsg_type = SCM_RIGHTS ;
137 std::memcpy( CMSG_DATA(cmsg) , &fd_to_send ,
sizeof(
int) ) ;
140 return ::sendmsg( fd , &msg , flags | MSG_NOSIGNAL ) ;
143ssize_t
G::Msg::recv(
int fd ,
void * buffer , std::size_t size ,
int flags )
noexcept
145 return ::recv( fd , buffer , size , flags ) ;
148ssize_t
G::Msg::recvfrom(
int fd ,
void * buffer , std::size_t size ,
int flags ,
149 sockaddr * address_p , socklen_t * address_np )
noexcept
151 return ::recvfrom( fd , buffer , size , flags , address_p , address_np ) ;
156 sockaddr * address_p , socklen_t * address_np ,
int * fd_received_p )
158 if( fd_received_p ==
nullptr )
159 return recvfrom( fd , buffer , size , flags , address_p , address_np ) ;
161 struct ::msghdr msg {} ;
163 msg.msg_name = address_p ;
164 msg.msg_namelen = address_np ==
nullptr ? socklen_t(0) : *address_np ;
166 struct ::iovec io {} ;
167 io.iov_base = buffer ;
172 std::array<char,CMSG_SPACE(
sizeof(
int))> control_buffer {} ;
173 msg.msg_control = &control_buffer[0] ;
174 msg.msg_controllen = control_buffer.size() ;
176 ssize_t rc = ::recvmsg( fd , &msg , flags ) ;
178 if( rc >= 0 && msg.msg_controllen > 0U && fd_received_p !=
nullptr )
180 struct cmsghdr * cmsg = CMSG_FIRSTHDR( &msg ) ;
181 if( cmsg !=
nullptr && cmsg->cmsg_type == SCM_RIGHTS )
183 std::memcpy( fd_received_p , CMSG_DATA(cmsg) ,
sizeof(
int) ) ;
186 if( rc >= 0 && address_np !=
nullptr )
188 *address_np = msg.msg_namelen ;
209template <
typename Tin,
typename Tout,
typename Fn1,
typename Fn2>
210std::size_t G::MsgImp::copy( Tin in_begin , Tin in_end , Tout out_begin , Tout ,
211 Fn1 fn_convert , Fn2 fn_empty )
213 return std::distance( out_begin ,
214 std::remove_if( out_begin ,
215 std::transform( in_begin , in_end , out_begin , fn_convert ) ,
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.
A class like c++17's std::string_view.