Skip to content

Commit 0792cde

Browse files
committed
fix(iocp): map portable message flags to native values in the UDP service
The IOCP UDP service passed the portable message_flags bits straight to the WSA send/recv calls, but the portable values do not match the native MSG_* constants: peek and out_of_band are swapped. Route all four operations through to_native_msg_flags() like the other backends, and use the lowercase <winsock2.h> spelling in msg_flags.hpp so its now-live Windows branch resolves on case-sensitive MinGW installs.
1 parent 0be082a commit 0792cde

4 files changed

Lines changed: 117 additions & 6 deletions

File tree

‎include/boost/corosio/message_flags.hpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace boost::corosio {
1616
1717
Platform-agnostic flag values that are mapped to native
1818
constants (MSG_PEEK, MSG_OOB, MSG_DONTROUTE) at the
19-
syscall boundary in the reactor implementation.
19+
syscall boundary in each backend implementation.
2020
*/
2121
enum class message_flags : int
2222
{

‎include/boost/corosio/native/detail/iocp/win_udp_service.hpp‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include <boost/corosio/native/detail/endpoint_convert.hpp>
2828
#include <boost/corosio/native/detail/make_err.hpp>
29+
#include <boost/corosio/native/detail/msg_flags.hpp>
2930
#include <boost/corosio/detail/dispatch_coro.hpp>
3031

3132
#include <cstring>
@@ -447,7 +448,7 @@ win_udp_socket_internal::send_to(
447448

448449
int result = ::WSASendTo(
449450
socket_, op.wsabufs, op.wsabuf_count, nullptr,
450-
static_cast<DWORD>(flags),
451+
static_cast<DWORD>(to_native_msg_flags(flags)),
451452
reinterpret_cast<sockaddr*>(&op.dest_storage), op.dest_len, &op,
452453
nullptr);
453454

@@ -514,7 +515,7 @@ win_udp_socket_internal::recv_from(
514515
op.wsabufs[i].len = static_cast<ULONG>(bufs[i].size());
515516
}
516517

517-
op.flags = static_cast<DWORD>(flags);
518+
op.flags = static_cast<DWORD>(to_native_msg_flags(flags));
518519
std::memset(&op.source_storage, 0, sizeof(op.source_storage));
519520
op.source_len = sizeof(op.source_storage);
520521

@@ -611,7 +612,7 @@ win_udp_socket_internal::send(
611612

612613
int result = ::WSASend(
613614
socket_, op.wsabufs, op.wsabuf_count, nullptr,
614-
static_cast<DWORD>(flags), &op, nullptr);
615+
static_cast<DWORD>(to_native_msg_flags(flags)), &op, nullptr);
615616

616617
if (result == SOCKET_ERROR)
617618
{
@@ -670,7 +671,7 @@ win_udp_socket_internal::recv(
670671
op.wsabufs[i].len = static_cast<ULONG>(bufs[i].size());
671672
}
672673

673-
op.flags = static_cast<DWORD>(flags);
674+
op.flags = static_cast<DWORD>(to_native_msg_flags(flags));
674675

675676
int result = ::WSARecv(
676677
socket_, op.wsabufs, op.wsabuf_count, nullptr, &op.flags, &op, nullptr);

‎include/boost/corosio/native/detail/msg_flags.hpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#ifndef NOMINMAX
2222
#define NOMINMAX
2323
#endif
24-
#include <WinSock2.h>
24+
#include <winsock2.h>
2525
#endif
2626

2727
namespace boost::corosio::detail {

‎test/unit/udp_socket.cpp‎

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,114 @@ struct udp_socket_test
10191019
ioc.run();
10201020
}
10211021

1022+
// message_flags::peek must map to the native peek flag on every
1023+
// backend; a raw pass-through of the portable value selects the
1024+
// wrong native flag.
1025+
void testRecvPeek()
1026+
{
1027+
io_context ioc(Backend);
1028+
1029+
udp_socket a(ioc);
1030+
udp_socket b(ioc);
1031+
1032+
BOOST_TEST(!b.open());
1033+
auto ec = b.bind(endpoint(ipv4_address::loopback(), 0));
1034+
BOOST_TEST_EQ(ec, std::error_code{});
1035+
auto b_ep = b.local_endpoint();
1036+
1037+
bool done = false;
1038+
auto task = [](udp_socket& a, udp_socket& b, endpoint dest,
1039+
bool& d) -> capy::task<> {
1040+
auto [ec1] = co_await a.connect(dest);
1041+
BOOST_TEST_EQ(ec1, std::error_code{});
1042+
auto [ec2] = co_await b.connect(a.local_endpoint());
1043+
BOOST_TEST_EQ(ec2, std::error_code{});
1044+
1045+
char const msg[] = "peek test";
1046+
auto [se, sn] =
1047+
co_await a.send(capy::const_buffer(msg, sizeof(msg)));
1048+
BOOST_TEST_EQ(se, std::error_code{});
1049+
BOOST_TEST_EQ(sn, sizeof(msg));
1050+
1051+
// Peek -- should not consume
1052+
char buf1[64] = {};
1053+
auto [re1, rn1] = co_await b.recv(
1054+
capy::mutable_buffer(buf1, sizeof(buf1)),
1055+
message_flags::peek);
1056+
BOOST_TEST_EQ(re1, std::error_code{});
1057+
BOOST_TEST_EQ(rn1, sizeof(msg));
1058+
BOOST_TEST_EQ(std::strcmp(buf1, "peek test"), 0);
1059+
1060+
// Normal recv -- should get the same datagram
1061+
char buf2[64] = {};
1062+
auto [re2, rn2] = co_await b.recv(
1063+
capy::mutable_buffer(buf2, sizeof(buf2)));
1064+
BOOST_TEST_EQ(re2, std::error_code{});
1065+
BOOST_TEST_EQ(rn2, sizeof(msg));
1066+
BOOST_TEST_EQ(std::strcmp(buf2, "peek test"), 0);
1067+
d = true;
1068+
};
1069+
1070+
auto ex = ioc.get_executor();
1071+
capy::run_async(ex)(task(a, b, b_ep, done));
1072+
ioc.run();
1073+
BOOST_TEST(done);
1074+
}
1075+
1076+
void testRecvFromPeek()
1077+
{
1078+
io_context ioc(Backend);
1079+
1080+
udp_socket a(ioc);
1081+
udp_socket b(ioc);
1082+
1083+
BOOST_TEST(!a.open());
1084+
BOOST_TEST(!b.open());
1085+
auto eca = a.bind(endpoint(ipv4_address::loopback(), 0));
1086+
BOOST_TEST_EQ(eca, std::error_code{});
1087+
auto ecb = b.bind(endpoint(ipv4_address::loopback(), 0));
1088+
BOOST_TEST_EQ(ecb, std::error_code{});
1089+
auto a_port = a.local_endpoint().port();
1090+
auto b_ep = b.local_endpoint();
1091+
1092+
bool done = false;
1093+
auto task = [](udp_socket& a, udp_socket& b, endpoint dest,
1094+
std::uint16_t sender_port, bool& d) -> capy::task<> {
1095+
char const msg[] = "recv_from peek";
1096+
auto [se, sn] = co_await a.send_to(
1097+
capy::const_buffer(msg, sizeof(msg)), dest);
1098+
BOOST_TEST_EQ(se, std::error_code{});
1099+
BOOST_TEST_EQ(sn, sizeof(msg));
1100+
1101+
// Peek via recv_from -- should not consume
1102+
char buf1[64] = {};
1103+
endpoint src1;
1104+
auto [re1, rn1] = co_await b.recv_from(
1105+
capy::mutable_buffer(buf1, sizeof(buf1)), src1,
1106+
message_flags::peek);
1107+
BOOST_TEST_EQ(re1, std::error_code{});
1108+
BOOST_TEST_EQ(rn1, sizeof(msg));
1109+
BOOST_TEST_EQ(std::strcmp(buf1, "recv_from peek"), 0);
1110+
BOOST_TEST_EQ(src1.port(), sender_port);
1111+
1112+
// Normal recv_from -- should get the same datagram
1113+
char buf2[64] = {};
1114+
endpoint src2;
1115+
auto [re2, rn2] = co_await b.recv_from(
1116+
capy::mutable_buffer(buf2, sizeof(buf2)), src2);
1117+
BOOST_TEST_EQ(re2, std::error_code{});
1118+
BOOST_TEST_EQ(rn2, sizeof(msg));
1119+
BOOST_TEST_EQ(std::strcmp(buf2, "recv_from peek"), 0);
1120+
BOOST_TEST_EQ(src2.port(), sender_port);
1121+
d = true;
1122+
};
1123+
1124+
auto ex = ioc.get_executor();
1125+
capy::run_async(ex)(task(a, b, b_ep, a_port, done));
1126+
ioc.run();
1127+
BOOST_TEST(done);
1128+
}
1129+
10221130
void testSendRecvConnectedV6()
10231131
{
10241132
io_context ioc(Backend);
@@ -1896,6 +2004,8 @@ struct udp_socket_test
18962004
testConnect();
18972005
testConnectAutoOpen();
18982006
testSendRecvConnected();
2007+
testRecvPeek();
2008+
testRecvFromPeek();
18992009
testSendRecvConnectedV6();
19002010
testCancelConnectedRecv();
19012011
testMulticastLoopHops();

0 commit comments

Comments
 (0)