Reputation: 303
https://github.com/ThinkalVB/RTDS-Server
I am making a simple UDP IPv6 server that prints version of the UDP packet sent by the remote endpoint. But this code is acting strangely. When sending IPv6 and IPv4 packets it is printing IPv6
. What is that I am doing wrong? [Testing in Win10 with Packet Sender Portable 6.2.3 (127.0.0.1 and ::1)]
#include <asio.hpp>
#include <iostream>
#include "udp_peer.h"
#include <thread>
asio::io_context ioContext;
asio::io_context::work worker(ioContext);
void runServer()
{
ioContext.run();
}
int main()
{
asio::ip::udp::endpoint mUDPep(asio::ip::udp::v6(), 321);
asio::ip::udp::socket mUDPsock(ioContext);
std::thread thread(runServer);
thread.detach();
asio::error_code ec;
UDPpeer udpPeer(&mUDPsock); // Ignore this, it contains the character array
asio::ip::udp::endpoint ep;
mUDPsock.open(mUDPep.protocol(), ec);
mUDPsock.bind(mUDPep, ec);
while (true)
{
auto dataSize = mUDPsock.receive_from(udpPeer.getReadBuffer(), ep);
if (ep.address().is_v4())
std::cout << "IPv4";
else
std::cout << "IPv6";
}
}
Upvotes: 2
Views: 498
Reputation: 392833
You're only listening on v6.
The ep
do not dictate how you receive.
Your v6 endpoint is able to receive both. Print the actual endpoint to see:
#include <boost/asio.hpp>
#include <iostream>
namespace asio = boost::asio;
using asio::ip::udp;
int main() {
asio::thread_pool context(1);
udp::socket sock(context, {udp::v6(), 8888});
udp::endpoint ep;
char arr[4096];
while (true) {
/*auto n =*/ sock.receive_from(asio::buffer(arr), ep);
std::cout
<< std::boolalpha << ep.address().is_v4() << " "
<< ep << "\n";
}
context.join();
}
Now sending two packets:
echo -n "hello world $RANDOM" | nc -6 -w 0 -u ::1 8888
echo -n "hello world $RANDOM" | nc -4 -w 0 -u 127.0.0.1 8888
Prints:
false [::1]:49972
false [::ffff:127.0.0.1]:34368
For comparison, saying
udp::socket sock(context, {udp::v4(), 8888});
instead simply doesn't receive the v6 packet:true 127.0.0.1:39805
In other words, because your socket is bound to v6, the address you get is mapped as if with:
if (a.is_v4())
return asio::ip::address_v6::v4_mapped(a.to_v4());
Check whether the v6 is v4 mapped or compatible:
asio::ip::address_v4 a4;
if (a6.is_v4_compatible() || a6.is_v4_mapped())
a4 = a6.to_v4();
Looks like the more modern interface for this is going to be something like
a4 = make_address_v4(asio::ip::v4_mapped, a6);
#include <boost/asio.hpp>
#include <iostream>
namespace asio = boost::asio;
using asio::ip::udp;
int main() {
asio::thread_pool context(1);
udp::socket sock(context, {udp::v6(), 8888});
udp::endpoint ep;
char arr[4096];
for (auto n=2; n--;) {
/*auto n =*/ sock.receive_from(asio::buffer(arr), ep);
asio::ip::address_v4 a4;
{
auto a6 = ep.address().to_v6();
if (a6.is_v4_compatible() || a6.is_v4_mapped())
a4 = a6.to_v4();
}
std::cout
<< (a4.is_unspecified()? "not-mapped" : a4.to_string()) << " "
<< ep << "\n";
}
context.join();
}
Prints
127.0.0.1 [::ffff:127.0.0.1]:54859
not-mapped [::1]:36231
Upvotes: 2