/* * This is a real-world example used to debug a multicast issue. * * After sending an initial small packet to the --multicast-address, * this program will listen for packets on that multicast address, * and reply to each incoming packet with a small burst of reply * packets to the sender. * * It is included to serve as example for how to write UDP-based * code using uv-co, including interaction with multicast features. */ #include #include #include #include #include #include #include #include "uvco/exception.h" #include "uvco/name_resolution.h" #include "uvco/promise/promise.h" #include "uvco/run.h" #include "uvco/timer.h" #include "uvco/udp.h" #include #include #include #include #include #include #include #include using namespace uvco; struct Options { const Loop &loop; std::string listenAddress = "ff02::fb%wlp1s0"; std::string multicastAddress = "ff02::fb"; uint16_t port = 5353; }; Options parseOptions(const Loop &loop, int argc, const char **argv) { namespace po = boost::program_options; Options options{loop}; bool help = false; po::options_description desc; desc.add_options()("listen-address", po::value(&options.listenAddress), "Listen/connect address")( "multicast-address", po::value(&options.multicastAddress), "Listen/connect address")("port", po::value(&options.port), "Listen/connect port")( "help,h", po::bool_switch(&help), "Display help"); po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); if (help) { std::cerr << desc << '\n'; std::exit(0); } return options; } // Currently not used, but depending on the applicationi you can choose to reply // to incoming multicast packets. Promise sendSome(const Options &opt, AddressHandle dst, size_t packets = 5, int interval = 1) { Udp udp{opt.loop}; std::string message = "Hello back"; for (size_t i = 0; i < packets; i++) { co_await udp.send(message, dst); co_await sleep(opt.loop, 50 * interval); } udp.close(); } Promise printPackets(Options opt) { Udp udp{opt.loop}; std::vector> active; try { co_await udp.bind(opt.listenAddress, opt.port, UV_UDP_IPV6ONLY); udp.joinMulticast(opt.multicastAddress, opt.listenAddress); udp.setMulticastLoop(false); fmt::print(stderr, "waiting for packets\n"); while (true) { const auto [packet, from] = co_await udp.receiveOneFrom(); fmt::print("Received packet: {} from {}\n", packet, from.toString()); } } catch (const UvcoException &e) { fmt::print(stderr, "exception: {}\n", e.what()); } udp.close(); } int main(int argc, const char **argv) { runMain([&](const Loop &loop) { Options opt = parseOptions(loop, argc, argv); // Promise can be dropped! The coroutine still lives on the event loop. return printPackets(opt); }); }