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