Line data Source code
1 : #include "source/common/network/happy_eyeballs_connection_impl.h" 2 : 3 : #include "source/common/network/connection_impl.h" 4 : 5 : namespace Envoy { 6 : namespace Network { 7 : 8 : HappyEyeballsConnectionProvider::HappyEyeballsConnectionProvider( 9 : Event::Dispatcher& dispatcher, const std::vector<Address::InstanceConstSharedPtr>& address_list, 10 : const std::shared_ptr<const Upstream::UpstreamLocalAddressSelector>& 11 : upstream_local_address_selector, 12 : UpstreamTransportSocketFactory& socket_factory, 13 : TransportSocketOptionsConstSharedPtr transport_socket_options, 14 : const Upstream::HostDescriptionConstSharedPtr& host, 15 : const ConnectionSocket::OptionsSharedPtr options) 16 : : dispatcher_(dispatcher), address_list_(sortAddresses(address_list)), 17 : upstream_local_address_selector_(upstream_local_address_selector), 18 : socket_factory_(socket_factory), transport_socket_options_(transport_socket_options), 19 0 : host_(host), options_(options) {} 20 : 21 0 : bool HappyEyeballsConnectionProvider::hasNextConnection() { 22 0 : return next_address_ < address_list_.size(); 23 0 : } 24 : 25 0 : ClientConnectionPtr HappyEyeballsConnectionProvider::createNextConnection(const uint64_t id) { 26 0 : if (first_connection_created_) { 27 : // The stats for the first connection are handled in ActiveClient::ActiveClient 28 0 : host_->stats().cx_total_.inc(); 29 0 : host_->cluster().trafficStats()->upstream_cx_total_.inc(); 30 0 : } 31 0 : first_connection_created_ = true; 32 0 : ASSERT(hasNextConnection()); 33 0 : ENVOY_LOG_EVENT(debug, "happy_eyeballs_cx_attempt", "C[{}] address={}", id, 34 0 : address_list_[next_address_]->asStringView()); 35 0 : auto& address = address_list_[next_address_++]; 36 0 : auto upstream_local_address = 37 0 : upstream_local_address_selector_->getUpstreamLocalAddress(address, options_); 38 : 39 0 : return dispatcher_.createClientConnection( 40 0 : address, upstream_local_address.address_, 41 0 : socket_factory_.createTransportSocket(transport_socket_options_, host_), 42 0 : upstream_local_address.socket_options_, transport_socket_options_); 43 0 : } 44 : 45 0 : size_t HappyEyeballsConnectionProvider::nextConnection() { return next_address_; } 46 : 47 0 : size_t HappyEyeballsConnectionProvider::totalConnections() { return address_list_.size(); } 48 : 49 : namespace { 50 : bool hasMatchingAddressFamily(const Address::InstanceConstSharedPtr& a, 51 0 : const Address::InstanceConstSharedPtr& b) { 52 0 : return (a->type() == Address::Type::Ip && b->type() == Address::Type::Ip && 53 0 : a->ip()->version() == b->ip()->version()); 54 0 : } 55 : 56 : } // namespace 57 : 58 : std::vector<Address::InstanceConstSharedPtr> HappyEyeballsConnectionProvider::sortAddresses( 59 0 : const std::vector<Address::InstanceConstSharedPtr>& in) { 60 0 : std::vector<Address::InstanceConstSharedPtr> address_list; 61 0 : address_list.reserve(in.size()); 62 : // Iterator which will advance through all addresses matching the first family. 63 0 : auto first = in.begin(); 64 : // Iterator which will advance through all addresses not matching the first family. 65 : // This initial value is ignored and will be overwritten in the loop below. 66 0 : auto other = in.begin(); 67 0 : while (first != in.end() || other != in.end()) { 68 0 : if (first != in.end()) { 69 0 : address_list.push_back(*first); 70 0 : first = std::find_if(first + 1, in.end(), 71 0 : [&](const auto& val) { return hasMatchingAddressFamily(in[0], val); }); 72 0 : } 73 : 74 0 : if (other != in.end()) { 75 0 : other = std::find_if(other + 1, in.end(), 76 0 : [&](const auto& val) { return !hasMatchingAddressFamily(in[0], val); }); 77 : 78 0 : if (other != in.end()) { 79 0 : address_list.push_back(*other); 80 0 : } 81 0 : } 82 0 : } 83 0 : ASSERT(address_list.size() == in.size()); 84 0 : return address_list; 85 0 : } 86 : 87 : } // namespace Network 88 : } // namespace Envoy