Use sendmsg and readmsg for all socket send and receive operations on

non-Windows platforms.
This commit is contained in:
chris_kohlhoff 2006-03-22 05:00:03 +00:00
parent b723883877
commit 358c2d0c14
3 changed files with 107 additions and 255 deletions

View File

@ -270,16 +270,16 @@ public:
socket_base::message_flags flags, Error_Handler error_handler)
{
// Copy buffers into array.
socket_ops::bufs bufs[max_buffers];
socket_ops::buf bufs[max_buffers];
typename Const_Buffers::const_iterator iter = buffers.begin();
typename Const_Buffers::const_iterator end = buffers.end();
size_t i = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
asio::const_buffer buffer(*iter);
bufs[i].size = asio::buffer_size(buffer);
bufs[i].data = const_cast<void*>(
asio::buffer_cast<const void*>(buffer));
socket_ops::init_buf(bufs[i],
asio::buffer_cast<const void*>(buffer),
asio::buffer_size(buffer));
}
// Send the data.
@ -338,16 +338,16 @@ public:
}
// Copy buffers into array.
socket_ops::bufs bufs[max_buffers];
socket_ops::buf bufs[max_buffers];
typename Const_Buffers::const_iterator iter = buffers_.begin();
typename Const_Buffers::const_iterator end = buffers_.end();
size_t i = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
asio::const_buffer buffer(*iter);
bufs[i].size = asio::buffer_size(buffer);
bufs[i].data = const_cast<void*>(
asio::buffer_cast<const void*>(buffer));
socket_ops::init_buf(bufs[i],
asio::buffer_cast<const void*>(buffer),
asio::buffer_size(buffer));
}
// Send the data.
@ -413,16 +413,16 @@ public:
Error_Handler error_handler)
{
// Copy buffers into array.
socket_ops::bufs bufs[max_buffers];
socket_ops::buf bufs[max_buffers];
typename Const_Buffers::const_iterator iter = buffers.begin();
typename Const_Buffers::const_iterator end = buffers.end();
size_t i = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
asio::const_buffer buffer(*iter);
bufs[i].size = asio::buffer_size(buffer);
bufs[i].data = const_cast<void*>(
asio::buffer_cast<const void*>(buffer));
socket_ops::init_buf(bufs[i],
asio::buffer_cast<const void*>(buffer),
asio::buffer_size(buffer));
}
// Send the data.
@ -483,16 +483,16 @@ public:
}
// Copy buffers into array.
socket_ops::bufs bufs[max_buffers];
socket_ops::buf bufs[max_buffers];
typename Const_Buffers::const_iterator iter = buffers_.begin();
typename Const_Buffers::const_iterator end = buffers_.end();
size_t i = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
asio::const_buffer buffer(*iter);
bufs[i].size = asio::buffer_size(buffer);
bufs[i].data = const_cast<void*>(
asio::buffer_cast<const void*>(buffer));
socket_ops::init_buf(bufs[i],
asio::buffer_cast<const void*>(buffer),
asio::buffer_size(buffer));
}
// Send the data.
@ -560,15 +560,16 @@ public:
socket_base::message_flags flags, Error_Handler error_handler)
{
// Copy buffers into array.
socket_ops::bufs bufs[max_buffers];
socket_ops::buf bufs[max_buffers];
typename Mutable_Buffers::const_iterator iter = buffers.begin();
typename Mutable_Buffers::const_iterator end = buffers.end();
size_t i = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
asio::mutable_buffer buffer(*iter);
bufs[i].size = asio::buffer_size(buffer);
bufs[i].data = asio::buffer_cast<void*>(buffer);
socket_ops::init_buf(bufs[i],
asio::buffer_cast<void*>(buffer),
asio::buffer_size(buffer));
}
// Receive some data.
@ -634,15 +635,16 @@ public:
}
// Copy buffers into array.
socket_ops::bufs bufs[max_buffers];
socket_ops::buf bufs[max_buffers];
typename Mutable_Buffers::const_iterator iter = buffers_.begin();
typename Mutable_Buffers::const_iterator end = buffers_.end();
size_t i = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
asio::mutable_buffer buffer(*iter);
bufs[i].size = asio::buffer_size(buffer);
bufs[i].data = asio::buffer_cast<void*>(buffer);
socket_ops::init_buf(bufs[i],
asio::buffer_cast<void*>(buffer),
asio::buffer_size(buffer));
}
// Receive some data.
@ -721,15 +723,16 @@ public:
Error_Handler error_handler)
{
// Copy buffers into array.
socket_ops::bufs bufs[max_buffers];
socket_ops::buf bufs[max_buffers];
typename Mutable_Buffers::const_iterator iter = buffers.begin();
typename Mutable_Buffers::const_iterator end = buffers.end();
size_t i = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
asio::mutable_buffer buffer(*iter);
bufs[i].size = asio::buffer_size(buffer);
bufs[i].data = asio::buffer_cast<void*>(buffer);
socket_ops::init_buf(bufs[i],
asio::buffer_cast<void*>(buffer),
asio::buffer_size(buffer));
}
// Receive some data.
@ -801,15 +804,16 @@ public:
}
// Copy buffers into array.
socket_ops::bufs bufs[max_buffers];
socket_ops::buf bufs[max_buffers];
typename Mutable_Buffers::const_iterator iter = buffers_.begin();
typename Mutable_Buffers::const_iterator end = buffers_.end();
size_t i = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
{
asio::mutable_buffer buffer(*iter);
bufs[i].size = asio::buffer_size(buffer);
bufs[i].data = asio::buffer_cast<void*>(buffer);
socket_ops::init_buf(bufs[i],
asio::buffer_cast<void*>(buffer),
asio::buffer_size(buffer));
}
// Receive some data.

View File

@ -22,7 +22,6 @@
#include <cstdlib>
#include <cstring>
#include <cerrno>
#include <vector>
#include <boost/detail/workaround.hpp>
#include "asio/detail/pop_options.hpp"
@ -102,287 +101,138 @@ inline int listen(socket_type s, int backlog)
return error_wrapper(::listen(s, backlog));
}
struct bufs
#if defined(BOOST_WINDOWS)
typedef WSABUF buf;
#else // defined(BOOST_WINDOWS)
typedef iovec buf;
#endif // defined(BOOST_WINDOWS)
inline void init_buf(buf& b, void* data, size_t size)
{
void* data;
size_t size;
};
#if defined(BOOST_WINDOWS)
b.buf = static_cast<char*>(data);
b.len = static_cast<u_long>(size);
#else // defined(BOOST_WINDOWS)
b.iov_base = data;
b.iov_len = size;
#endif // defined(BOOST_WINDOWS)
}
enum { max_bufs = 16 };
inline void init_buf(buf& b, const void* data, size_t size)
{
#if defined(BOOST_WINDOWS)
b.buf = static_cast<char*>(const_cast<void*>(data));
b.len = static_cast<u_long>(size);
#else // defined(BOOST_WINDOWS)
b.iov_base = const_cast<void*>(data);
b.iov_len = size;
#endif // defined(BOOST_WINDOWS)
}
inline int recv(socket_type s, bufs* b, size_t count, int flags)
inline int recv(socket_type s, buf* bufs, size_t count, int flags)
{
set_error(0);
#if defined(BOOST_WINDOWS)
// Copy buffers into WSABUF array.
WSABUF recv_bufs[max_bufs];
if (count > max_bufs)
count = max_bufs;
for (size_t i = 0; i < count; ++i)
{
recv_bufs[i].len = static_cast<u_long>(b[i].size);
recv_bufs[i].buf = static_cast<char*>(b[i].data);
}
// Receive some data.
DWORD recv_buf_count = static_cast<DWORD>(count);
DWORD bytes_transferred = 0;
DWORD recv_flags = flags;
int result = error_wrapper(::WSARecv(s, recv_bufs,
int result = error_wrapper(::WSARecv(s, bufs,
recv_buf_count, &bytes_transferred, &recv_flags, 0, 0));
if (result != 0)
return -1;
return bytes_transferred;
#else // defined(BOOST_WINDOWS)
if (count == 1)
{
// We only have to receive into a single buffer, so use normal recv call.
return error_wrapper(::recv(s, b[0].data, b[0].size, flags));
}
else if (flags == 0)
{
// No flags have been specified so we can perform this receive operation
// using a vectored-read function, i.e. readv.
// Copy buffers into iovec array.
iovec recv_bufs[max_bufs];
if (count > max_bufs)
count = max_bufs;
for (size_t i = 0; i < count; ++i)
{
recv_bufs[i].iov_len = b[i].size;
recv_bufs[i].iov_base = b[i].data;
}
// Receive some data.
return error_wrapper(::readv(s, recv_bufs, count));
}
else
{
// Socket flags have been supplied so receive into a temporary buffer and
// then copy the data to the caller-supplied buffers.
// Create a buffer of the appropriate size.
size_t buf_size = 0;
for (size_t i = 0; i < count; ++i)
buf_size += b[i].size;
std::vector<char> buffer(buf_size);
// Receive some data.
int result = error_wrapper(::recv(s, &buffer[0], buf_size, flags));
if (result <= 0)
return result;
// Copy to caller-supplied buffers.
using namespace std; // For memcpy.
size_t bytes_avail = result;
size_t bytes_copied = 0;
for (size_t i = 0; i < count && bytes_avail > 0; ++i)
{
size_t size = (b[i].size < bytes_avail) ? b[i].size : bytes_avail;
memcpy(b[i].data, &buffer[bytes_copied], size);
bytes_copied += size;
bytes_avail -= size;
}
return result;
}
msghdr msg;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = bufs;
msg.msg_iovlen = count;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
return error_wrapper(::recvmsg(s, &msg, flags));
#endif // defined(BOOST_WINDOWS)
}
inline int recvfrom(socket_type s, bufs* b, size_t count, int flags,
inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
socket_addr_type* addr, socket_addr_len_type* addrlen)
{
set_error(0);
#if defined(BOOST_WINDOWS)
// Copy buffers into WSABUF array.
WSABUF recv_bufs[max_bufs];
if (count > max_bufs)
count = max_bufs;
for (size_t i = 0; i < count; ++i)
{
recv_bufs[i].len = static_cast<u_long>(b[i].size);
recv_bufs[i].buf = static_cast<char*>(b[i].data);
}
// Receive some data.
DWORD recv_buf_count = static_cast<DWORD>(count);
DWORD bytes_transferred = 0;
DWORD recv_flags = flags;
int result = error_wrapper(::WSARecvFrom(s, recv_bufs, recv_buf_count,
int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count,
&bytes_transferred, &recv_flags, addr, addrlen, 0, 0));
if (result != 0)
return -1;
return bytes_transferred;
#else // defined(BOOST_WINDOWS)
if (count == 1)
{
// We only have to receive into a single buffer, so use normal recvfrom
// call.
return error_wrapper(::recvfrom(s,
b[0].data, b[0].size, flags, addr, addrlen));
}
else
{
// We have to receive into multiple buffers, so receive into a temporary
// buffer and then copy the data to the caller-supplied buffers.
// Create a buffer of the appropriate size.
size_t buf_size = 0;
for (size_t i = 0; i < count; ++i)
buf_size += b[i].size;
std::vector<char> buffer(buf_size);
// Receive some data.
int result = error_wrapper(::recvfrom(s,
&buffer[0], buf_size, flags, addr, addrlen));
if (result <= 0)
return result;
// Copy to caller-supplied buffers.
using namespace std; // For memcpy.
size_t bytes_avail = result;
size_t bytes_copied = 0;
for (size_t i = 0; i < count && bytes_avail > 0; ++i)
{
size_t size = (b[i].size < bytes_avail) ? b[i].size : bytes_avail;
memcpy(b[i].data, &buffer[bytes_copied], size);
bytes_copied += size;
bytes_avail -= size;
}
return result;
}
msghdr msg;
msg.msg_name = addr;
msg.msg_namelen = *addrlen;
msg.msg_iov = bufs;
msg.msg_iovlen = count;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
int result = error_wrapper(::recvmsg(s, &msg, flags));
*addrlen = msg.msg_namelen;
return result;
#endif // defined(BOOST_WINDOWS)
}
inline int send(socket_type s, const bufs* b, size_t count, int flags)
inline int send(socket_type s, const buf* bufs, size_t count, int flags)
{
set_error(0);
#if defined(BOOST_WINDOWS)
// Copy buffers into WSABUF array.
WSABUF send_bufs[max_bufs];
if (count > max_bufs)
count = max_bufs;
for (size_t i = 0; i < count; ++i)
{
send_bufs[i].len = static_cast<u_long>(b[i].size);
send_bufs[i].buf = static_cast<char*>(b[i].data);
}
// Send the data.
DWORD send_buf_count = static_cast<DWORD>(count);
DWORD bytes_transferred = 0;
DWORD send_flags = flags;
int result = error_wrapper(::WSASend(s, send_bufs,
int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs),
send_buf_count, &bytes_transferred, send_flags, 0, 0));
if (result != 0)
return -1;
return bytes_transferred;
#else // defined(BOOST_WINDOWS)
if (count == 1)
{
// We only have to send a single buffer, so use normal send call.
return error_wrapper(::send(s, b[0].data, b[0].size, flags));
}
else if (flags == 0)
{
// No flags have been specified so we can perform this send operation using
// a vectored-write function, i.e. writev.
// Copy buffers into iovec array.
iovec send_bufs[max_bufs];
if (count > max_bufs)
count = max_bufs;
for (size_t i = 0; i < count; ++i)
{
send_bufs[i].iov_len = b[i].size;
send_bufs[i].iov_base = b[i].data;
}
// Send the data.
return error_wrapper(::writev(s, send_bufs, count));
}
else
{
// Socket flags have been supplied so copy the caller-supplied buffers into
// a temporary buffer for sending.
// Create a buffer of the appropriate size.
size_t buf_size = 0;
for (size_t i = 0; i < count; ++i)
buf_size += b[i].size;
std::vector<char> buffer(buf_size);
// Copy data from caller-supplied buffers.
using namespace std; // For memcpy.
size_t bytes_copied = 0;
for (size_t i = 0; i < count; ++i)
{
memcpy(&buffer[bytes_copied], b[i].data, b[i].size);
bytes_copied += b[i].size;
}
// Receive some data.
return error_wrapper(::send(s, &buffer[0], buf_size, flags));
}
msghdr msg;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = const_cast<buf*>(bufs);
msg.msg_iovlen = count;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
return error_wrapper(::sendmsg(s, &msg, flags));
#endif // defined(BOOST_WINDOWS)
}
inline int sendto(socket_type s, const bufs* b, size_t count, int flags,
inline int sendto(socket_type s, const buf* bufs, size_t count, int flags,
const socket_addr_type* addr, socket_addr_len_type addrlen)
{
set_error(0);
#if defined(BOOST_WINDOWS)
// Copy buffers into WSABUF array.
WSABUF send_bufs[max_bufs];
if (count > max_bufs)
count = max_bufs;
for (size_t i = 0; i < count; ++i)
{
send_bufs[i].len = static_cast<u_long>(b[i].size);
send_bufs[i].buf = static_cast<char*>(b[i].data);
}
// Send the data.
DWORD send_buf_count = static_cast<DWORD>(count);
DWORD bytes_transferred = 0;
int result = ::WSASendTo(s, send_bufs, send_buf_count,
int result = ::WSASendTo(s, const_cast<buf*>(bufs), send_buf_count,
&bytes_transferred, flags, addr, addrlen, 0, 0);
if (result != 0)
return -1;
return bytes_transferred;
#else // defined(BOOST_WINDOWS)
if (count == 1)
{
// We only have to send a single buffer, so use normal sendto call.
return error_wrapper(::sendto(s,
b[0].data, b[0].size, flags, addr, addrlen));
}
else
{
// Socket flags have been supplied so copy the caller-supplied buffers into
// a temporary buffer for sending.
// Create a buffer of the appropriate size.
size_t buf_size = 0;
for (size_t i = 0; i < count; ++i)
buf_size += b[i].size;
std::vector<char> buffer(buf_size);
// Copy data from caller-supplied buffers.
using namespace std; // For memcpy.
size_t bytes_copied = 0;
for (size_t i = 0; i < count; ++i)
{
memcpy(&buffer[bytes_copied], b[i].data, b[i].size);
bytes_copied += b[i].size;
}
// Receive some data.
return error_wrapper(::sendto(s,
&buffer[0], buf_size, flags, addr, addrlen));
}
msghdr msg;
msg.msg_name = const_cast<socket_addr_type*>(addr);
msg.msg_namelen = addrlen;
msg.msg_iov = const_cast<buf*>(bufs);
msg.msg_iovlen = count;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
return error_wrapper(::sendmsg(s, &msg, flags));
#endif // defined(BOOST_WINDOWS)
}

View File

@ -132,9 +132,8 @@ public:
void interrupt()
{
char byte = 0;
socket_ops::bufs b;
b.data = &byte;
b.size = 1;
socket_ops::buf b;
socket_ops::init_buf(b, &byte, 1);
socket_ops::send(write_descriptor_, &b, 1, 0);
}
@ -142,9 +141,8 @@ public:
bool reset()
{
char data[1024];
socket_ops::bufs b;
b.data = data;
b.size = sizeof(data);
socket_ops::buf b;
socket_ops::init_buf(b, data, sizeof(data));
int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0);
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))