address bind_to_device(io_service& ios, Socket& sock , bool ipv4, char const* device_name, int port, error_code& ec) { boost::asio::ip::tcp::endpoint bind_ep(address_v4::any(), port); address ip = address::from_string(device_name, ec); if (!ec) { bind_ep.address(ip); // it appears to be an IP. Just bind to that address sock.bind(bind_ep, ec); return bind_ep.address(); } ec.clear(); #ifdef SO_BINDTODEVICE // try to use SO_BINDTODEVICE here, if that exists. If it fails, // fall back to the mechanism we have below sock.set_option(bind_to_device_opt(device_name), ec); if (ec) #endif { ec.clear(); // TODO: 2 this could be done more efficiently by just looking up // the interface with the given name, maybe even with if_nametoindex() std::vector<ip_interface> ifs = enum_net_interfaces(ios, ec); if (ec) return bind_ep.address(); bool found = false; for (int i = 0; i < int(ifs.size()); ++i) { // we're looking for a specific interface, and its address // (which must be of the same family as the address we're // connecting to) if (strcmp(ifs[i].name, device_name) != 0) continue; if (ifs[i].interface_address.is_v4() != ipv4) continue; bind_ep.address(ifs[i].interface_address); found = true; break; } if (!found) { ec = error_code(boost::system::errc::no_such_device, generic_category()); return bind_ep.address(); } } sock.bind(bind_ep, ec); return bind_ep.address(); }
address bind_socket_to_device(io_service& ios, Socket& sock , boost::asio::ip::tcp const& protocol , char const* device_name, int port, error_code& ec) { tcp::endpoint bind_ep(address_v4::any(), std::uint16_t(port)); address ip = make_address(device_name, ec); if (!ec) { #if TORRENT_USE_IPV6 // this is to cover the case where "0.0.0.0" is considered any IPv4 or // IPv6 address. If we're asking to be bound to an IPv6 address and // providing 0.0.0.0 as the device, turn it into "::" if (ip == address_v4::any() && protocol == boost::asio::ip::tcp::v6()) ip = address_v6::any(); #endif bind_ep.address(ip); // it appears to be an IP. Just bind to that address sock.bind(bind_ep, ec); return bind_ep.address(); } ec.clear(); #if TORRENT_HAS_BINDTODEVICE // try to use SO_BINDTODEVICE here, if that exists. If it fails, // fall back to the mechanism we have below sock.set_option(aux::bind_to_device(device_name), ec); if (ec) #endif { ec.clear(); // TODO: 2 this could be done more efficiently by just looking up // the interface with the given name, maybe even with if_nametoindex() std::vector<ip_interface> ifs = enum_net_interfaces(ios, ec); if (ec) return bind_ep.address(); bool found = false; for (auto const& iface : ifs) { // we're looking for a specific interface, and its address // (which must be of the same family as the address we're // connecting to) if (std::strcmp(iface.name, device_name) != 0) continue; if (iface.interface_address.is_v4() != (protocol == boost::asio::ip::tcp::v4())) continue; bind_ep.address(iface.interface_address); found = true; break; } if (!found) { ec = error_code(boost::system::errc::no_such_device, generic_category()); return bind_ep.address(); } } sock.bind(bind_ep, ec); return bind_ep.address(); }