|
1 | 1 | #include "resolve_attempt_udp.h" |
2 | 2 | #include "api_config.h" |
| 3 | +#include "netinterfaces.h" |
3 | 4 | #include "resolver_impl.h" |
4 | 5 | #include "socket_utils.h" |
5 | 6 | #include <boost/asio/ip/multicast.hpp> |
|
9 | 10 | using namespace lsl; |
10 | 11 | namespace asio = lslboost::asio; |
11 | 12 | using err_t = const lslboost::system::error_code &; |
| 13 | +using asio::ip::multicast::outbound_interface; |
12 | 14 |
|
13 | 15 | resolve_attempt_udp::resolve_attempt_udp(asio::io_context &io, const udp &protocol, |
14 | 16 | const std::vector<udp::endpoint> &targets, const std::string &query, result_container &results, |
15 | 17 | std::mutex &results_mut, double cancel_after, cancellable_registry *registry) |
16 | 18 | : io_(io), results_(results), results_mut_(results_mut), cancel_after_(cancel_after), |
17 | 19 | cancelled_(false), targets_(targets), query_(query), unicast_socket_(io), |
18 | | - broadcast_socket_(io), multicast_socket_(io), recv_socket_(io), cancel_timer_(io) { |
| 20 | + broadcast_socket_(io), multicast_socket_(io), |
| 21 | + multicast_interfaces(api_config::get_instance()->multicast_interfaces), recv_socket_(io), |
| 22 | + cancel_timer_(io) { |
19 | 23 | // open the sockets that we might need |
20 | 24 | recv_socket_.open(protocol); |
21 | 25 | try { |
@@ -69,7 +73,7 @@ void resolve_attempt_udp::begin() { |
69 | 73 | // initiate the result gathering chain |
70 | 74 | receive_next_result(); |
71 | 75 | // initiate the send chain |
72 | | - send_next_query(targets_.begin()); |
| 76 | + send_next_query(targets_.begin(), multicast_interfaces.begin()); |
73 | 77 |
|
74 | 78 | // also initiate the cancel event, if desired |
75 | 79 | if (cancel_after_ != FOREVER) { |
@@ -143,27 +147,41 @@ void resolve_attempt_udp::handle_receive_outcome(error_code err, std::size_t len |
143 | 147 |
|
144 | 148 | // === send loop === |
145 | 149 |
|
146 | | -void resolve_attempt_udp::send_next_query(endpoint_list::const_iterator next) { |
147 | | - if (next == targets_.end() || cancelled_) return; |
148 | | - |
149 | | - udp::endpoint ep(*next++); |
150 | | - // endpoint matches our active protocol? |
151 | | - if (ep.protocol() == recv_socket_.local_endpoint().protocol()) { |
152 | | - // select socket to use |
153 | | - udp::socket &sock = |
154 | | - (ep.address() == asio::ip::address_v4::broadcast()) |
155 | | - ? broadcast_socket_ |
156 | | - : (ep.address().is_multicast() ? multicast_socket_ : unicast_socket_); |
157 | | - // and send the query over it |
158 | | - sock.async_send_to(lslboost::asio::buffer(query_msg_), ep, |
159 | | - [shared_this = shared_from_this(), next](err_t err, size_t /*unused*/) { |
160 | | - if (!shared_this->cancelled_ && err != asio::error::operation_aborted && |
161 | | - err != asio::error::not_connected && err != asio::error::not_socket) |
162 | | - shared_this->send_next_query(next); |
163 | | - }); |
| 150 | +void resolve_attempt_udp::send_next_query( |
| 151 | + endpoint_list::const_iterator next, mcast_interface_list::const_iterator mcit) { |
| 152 | + if (cancelled_ || mcit == multicast_interfaces.end()) return; |
| 153 | + auto proto = recv_socket_.local_endpoint().protocol(); |
| 154 | + if (next == targets_.begin()) { |
| 155 | + // Mismatching protocols? Skip this round |
| 156 | + if(mcit->addr.is_v4() != (proto==asio::ip::udp::v4())) |
| 157 | + next = targets_.end(); |
| 158 | + else |
| 159 | + multicast_socket_.set_option(mcit->addr.is_v4() ? outbound_interface(mcit->addr.to_v4()) |
| 160 | + : outbound_interface(mcit->ifindex)); |
| 161 | + } |
| 162 | + if (next != targets_.end()) { |
| 163 | + udp::endpoint ep(*next++); |
| 164 | + // endpoint matches our active protocol? |
| 165 | + if (ep.protocol() == recv_socket_.local_endpoint().protocol()) { |
| 166 | + // select socket to use |
| 167 | + udp::socket &sock = |
| 168 | + (ep.address() == asio::ip::address_v4::broadcast()) |
| 169 | + ? broadcast_socket_ |
| 170 | + : (ep.address().is_multicast() ? multicast_socket_ : unicast_socket_); |
| 171 | + // and send the query over it |
| 172 | + auto keepalive(shared_from_this()); |
| 173 | + sock.async_send_to( |
| 174 | + lslboost::asio::buffer(query_msg_), ep, [shared_this = shared_from_this(), next, mcit](err_t err, size_t /*unused*/) { |
| 175 | + if (!shared_this->cancelled_ && err != asio::error::operation_aborted && |
| 176 | + err != asio::error::not_connected && err != asio::error::not_socket) |
| 177 | + shared_this->send_next_query(next, mcit); |
| 178 | + }); |
| 179 | + } else |
| 180 | + // otherwise just go directly to the next query |
| 181 | + send_next_query(next, mcit); |
164 | 182 | } else |
165 | | - // otherwise just go directly to the next query |
166 | | - send_next_query(next); |
| 183 | + // Restart from the next interface |
| 184 | + send_next_query(targets_.begin(), ++mcit); |
167 | 185 | } |
168 | 186 |
|
169 | 187 | void resolve_attempt_udp::do_cancel() { |
|
0 commit comments