OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 1230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1241 } | 1241 } |
1242 | 1242 |
1243 Connection* top_connection = | 1243 Connection* top_connection = |
1244 (connections_.size() > 0) ? connections_[0] : nullptr; | 1244 (connections_.size() > 0) ? connections_[0] : nullptr; |
1245 | 1245 |
1246 // If necessary, switch to the new choice. Note that |top_connection| doesn't | 1246 // If necessary, switch to the new choice. Note that |top_connection| doesn't |
1247 // have to be writable to become the selected connection although it will | 1247 // have to be writable to become the selected connection although it will |
1248 // have higher priority if it is writable. | 1248 // have higher priority if it is writable. |
1249 MaybeSwitchSelectedConnection(top_connection, "sorting"); | 1249 MaybeSwitchSelectedConnection(top_connection, "sorting"); |
1250 | 1250 |
1251 UpdatePremierConnections(); | |
1252 | |
1251 // The controlled side can prune only if the selected connection has been | 1253 // The controlled side can prune only if the selected connection has been |
1252 // nominated because otherwise it may prune the connection that will be | 1254 // nominated because otherwise it may prune the connection that will be |
1253 // selected by the controlling side. | 1255 // selected by the controlling side. |
1254 // TODO(honghaiz): This is not enough to prevent a connection from being | 1256 // TODO(honghaiz): This is not enough to prevent a connection from being |
1255 // pruned too early because with aggressive nomination, the controlling side | 1257 // pruned too early because with aggressive nomination, the controlling side |
1256 // will nominate every connection until it becomes writable. | 1258 // will nominate every connection until it becomes writable. |
1257 if (ice_role_ == ICEROLE_CONTROLLING || | 1259 if (ice_role_ == ICEROLE_CONTROLLING || |
1258 (selected_connection_ && selected_connection_->nominated())) { | 1260 (selected_connection_ && selected_connection_->nominated())) { |
1259 PruneConnections(); | 1261 PruneConnections(); |
1260 } | 1262 } |
(...skipping 17 matching lines...) Expand all Loading... | |
1278 UpdateState(); | 1280 UpdateState(); |
1279 | 1281 |
1280 // Also possibly start pinging. | 1282 // Also possibly start pinging. |
1281 // We could start pinging if: | 1283 // We could start pinging if: |
1282 // * The first connection was created. | 1284 // * The first connection was created. |
1283 // * ICE credentials were provided. | 1285 // * ICE credentials were provided. |
1284 // * A TCP connection became connected. | 1286 // * A TCP connection became connected. |
1285 MaybeStartPinging(); | 1287 MaybeStartPinging(); |
1286 } | 1288 } |
1287 | 1289 |
1290 void P2PTransportChannel::UpdatePremierConnections() { | |
1291 // |connections_| has been sorted, so the first one in the list on a given | |
1292 // network is the premier connection, except that the selected connection | |
1293 // is always the premier connection on the network. | |
1294 premier_connection_by_network_name_.clear(); | |
1295 for (Connection* conn : connections_) { | |
1296 const std::string& network_name = conn->port()->Network()->name(); | |
1297 if (conn == selected_connection_ || | |
1298 premier_connection_by_network_name_.find(network_name) == | |
1299 premier_connection_by_network_name_.end()) { | |
1300 premier_connection_by_network_name_[network_name] = conn; | |
1301 } | |
1302 } | |
1303 } | |
1304 | |
1288 void P2PTransportChannel::PruneConnections() { | 1305 void P2PTransportChannel::PruneConnections() { |
1289 // We can prune any connection for which there is a connected, writable | 1306 // We can prune any connection for which there is a connected, writable |
1290 // connection on the same network with better or equal priority. We leave | 1307 // connection on the same network with better or equal priority. We leave |
1291 // those with better priority just in case they become writable later (at | 1308 // those with better priority just in case they become writable later (at |
1292 // which point, we would prune out the current selected connection). We leave | 1309 // which point, we would prune out the current selected connection). We leave |
1293 // connections on other networks because they may not be using the same | 1310 // connections on other networks because they may not be using the same |
1294 // resources and they may represent very distinct paths over which we can | 1311 // resources and they may represent very distinct paths over which we can |
1295 // switch. If the |premier| connection is not connected, we may be | 1312 // switch. If the |premier| connection is not connected, we may be |
1296 // reconnecting a TCP connection and temporarily do not prune connections in | 1313 // reconnecting a TCP connection and temporarily do not prune connections in |
1297 // this network. See the big comment in CompareConnectionStates. | 1314 // this network. See the big comment in CompareConnectionStates. |
1298 | 1315 for (Connection* conn : connections_) { |
1299 // Get a list of the networks that we are using. | 1316 // Do not prune connections if the current premier connection is weak on |
1300 std::set<rtc::Network*> networks; | |
1301 for (const Connection* conn : connections_) { | |
1302 networks.insert(conn->port()->Network()); | |
1303 } | |
1304 for (rtc::Network* network : networks) { | |
1305 Connection* premier = GetBestConnectionOnNetwork(network); | |
1306 // Do not prune connections if the current selected connection is weak on | |
1307 // this network. Otherwise, it may delete connections prematurely. | 1317 // this network. Otherwise, it may delete connections prematurely. |
1308 if (!premier || premier->weak()) { | 1318 Connection* premier = |
1319 premier_connection_by_network_name_[conn->port()->Network()->name()]; | |
1320 if (!premier || conn == premier || premier->weak()) { | |
1309 continue; | 1321 continue; |
1310 } | 1322 } |
1311 | 1323 if (CompareConnectionCandidates(premier, conn) >= 0) { |
1312 for (Connection* conn : connections_) { | 1324 conn->Prune(); |
1313 if ((conn != premier) && (conn->port()->Network() == network) && | |
1314 (CompareConnectionCandidates(premier, conn) >= 0)) { | |
1315 conn->Prune(); | |
1316 } | |
1317 } | 1325 } |
1318 } | 1326 } |
1319 } | 1327 } |
1320 | 1328 |
1321 // Change the selected connection, and let listeners know. | 1329 // Change the selected connection, and let listeners know. |
1322 void P2PTransportChannel::SwitchSelectedConnection(Connection* conn) { | 1330 void P2PTransportChannel::SwitchSelectedConnection(Connection* conn) { |
1323 // Note: if conn is NULL, the previous |selected_connection_| has been | 1331 // Note: if conn is NULL, the previous |selected_connection_| has been |
1324 // destroyed, so don't use it. | 1332 // destroyed, so don't use it. |
1325 Connection* old_selected_connection = selected_connection_; | 1333 Connection* old_selected_connection = selected_connection_; |
1326 selected_connection_ = conn; | 1334 selected_connection_ = conn; |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1444 bool P2PTransportChannel::ReadyToSend(Connection* connection) const { | 1452 bool P2PTransportChannel::ReadyToSend(Connection* connection) const { |
1445 // Note that we allow sending on an unreliable connection, because it's | 1453 // Note that we allow sending on an unreliable connection, because it's |
1446 // possible that it became unreliable simply due to bad chance. | 1454 // possible that it became unreliable simply due to bad chance. |
1447 // So this shouldn't prevent attempting to send media. | 1455 // So this shouldn't prevent attempting to send media. |
1448 return connection != nullptr && | 1456 return connection != nullptr && |
1449 (connection->writable() || | 1457 (connection->writable() || |
1450 connection->write_state() == Connection::STATE_WRITE_UNRELIABLE || | 1458 connection->write_state() == Connection::STATE_WRITE_UNRELIABLE || |
1451 PresumedWritable(connection)); | 1459 PresumedWritable(connection)); |
1452 } | 1460 } |
1453 | 1461 |
1454 // If we have a selected connection, return it, otherwise return top one in the | |
1455 // list (later we will mark it best). | |
1456 Connection* P2PTransportChannel::GetBestConnectionOnNetwork( | |
1457 rtc::Network* network) const { | |
1458 // If the selected connection is on this network, then it wins. | |
1459 if (selected_connection_ && | |
1460 (selected_connection_->port()->Network() == network)) { | |
1461 return selected_connection_; | |
1462 } | |
1463 | |
1464 // Otherwise, we return the top-most in sorted order. | |
1465 for (size_t i = 0; i < connections_.size(); ++i) { | |
1466 if (connections_[i]->port()->Network() == network) { | |
1467 return connections_[i]; | |
1468 } | |
1469 } | |
1470 | |
1471 return NULL; | |
1472 } | |
1473 | |
1474 // Handle any queued up requests | 1462 // Handle any queued up requests |
1475 void P2PTransportChannel::OnMessage(rtc::Message *pmsg) { | 1463 void P2PTransportChannel::OnMessage(rtc::Message *pmsg) { |
1476 switch (pmsg->message_id) { | 1464 switch (pmsg->message_id) { |
1477 case MSG_SORT_AND_UPDATE_STATE: | 1465 case MSG_SORT_AND_UPDATE_STATE: |
1478 SortConnectionsAndUpdateState(); | 1466 SortConnectionsAndUpdateState(); |
1479 break; | 1467 break; |
1480 case MSG_CHECK_AND_PING: | 1468 case MSG_CHECK_AND_PING: |
1481 OnCheckAndPing(); | 1469 OnCheckAndPing(); |
1482 break; | 1470 break; |
1483 case MSG_REGATHER_ON_FAILED_NETWORKS: | 1471 case MSG_REGATHER_ON_FAILED_NETWORKS: |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1541 return false; | 1529 return false; |
1542 } | 1530 } |
1543 | 1531 |
1544 // An never connected connection cannot be written to at all, so pinging is | 1532 // An never connected connection cannot be written to at all, so pinging is |
1545 // out of the question. However, if it has become WRITABLE, it is in the | 1533 // out of the question. However, if it has become WRITABLE, it is in the |
1546 // reconnecting state so ping is needed. | 1534 // reconnecting state so ping is needed. |
1547 if (!conn->connected() && !conn->writable()) { | 1535 if (!conn->connected() && !conn->writable()) { |
1548 return false; | 1536 return false; |
1549 } | 1537 } |
1550 | 1538 |
1551 // If the channel is weakly connected, ping all connections. | 1539 // Backup connections are pinged at a slower rate if the channel is strongly |
1552 if (weak()) { | 1540 // connected. |
1553 return true; | 1541 bool strongly_connected = !weak(); |
1554 } | 1542 if (strongly_connected && IsBackupConnection(conn)) { |
1555 | |
1556 // Always ping active connections regardless whether the channel is completed | |
1557 // or not, but backup connections are pinged at a slower rate. | |
1558 if (IsBackupConnection(conn)) { | |
1559 return conn->rtt_samples() == 0 || | 1543 return conn->rtt_samples() == 0 || |
1560 (now >= conn->last_ping_response_received() + | 1544 (now >= conn->last_ping_response_received() + |
1561 config_.backup_connection_ping_interval); | 1545 config_.backup_connection_ping_interval); |
1562 } | 1546 } |
1563 // Don't ping inactive non-backup connections. | 1547 |
1548 // If the premier connection is weakly connected, ping all connections on | |
Taylor Brandstetter
2016/10/04 02:08:10
Suggest changing this to "If the premier connectio
honghaiz3
2016/10/20 23:47:58
Done.
| |
1549 // the same network. Otherwise, do not ping those with a lower priority | |
1550 // (i.e., those having been pruned) or those which have timed out. | |
1551 auto iter = | |
1552 premier_connection_by_network_name_.find(conn->port()->Network()->name()); | |
1553 if (iter == premier_connection_by_network_name_.end() || !iter->second || | |
1554 iter->second->weak()) { | |
1555 return true; | |
1556 } | |
1557 | |
1558 // Don't ping inactive connections. | |
1564 if (!conn->active()) { | 1559 if (!conn->active()) { |
1565 return false; | 1560 return false; |
1566 } | 1561 } |
1567 | 1562 |
1568 // Do ping unwritable, active connections. | 1563 // Do ping unwritable, active connections. |
1569 if (!conn->writable()) { | 1564 if (!conn->writable()) { |
1570 return true; | 1565 return true; |
1571 } | 1566 } |
1572 | 1567 |
1573 // Ping writable, active connections if it's been long enough since the last | 1568 // Ping writable, active connections if it's been long enough since the last |
1574 // ping. | 1569 // ping. |
1575 int ping_interval = CalculateActiveWritablePingInterval(conn, now); | 1570 int ping_interval = CalculateActiveWritablePingInterval(conn, now); |
1576 return (now >= conn->last_ping_sent() + ping_interval); | 1571 return (now >= conn->last_ping_sent() + ping_interval); |
1577 } | 1572 } |
1578 | 1573 |
1579 bool P2PTransportChannel::IsSelectedConnectionPingable(int64_t now) { | 1574 bool P2PTransportChannel::IsPremierConnectionPingable( |
1580 if (!selected_connection_ || !selected_connection_->connected() || | 1575 Connection* premier_connection, |
1581 !selected_connection_->writable()) { | 1576 int64_t now) { |
1577 if (!premier_connection || !premier_connection->connected() || | |
1578 !premier_connection->writable() || | |
1579 premier_connection->state() == Connection::STATE_FAILED) { | |
Taylor Brandstetter
2016/10/04 02:08:09
Why did the "failed" check not exist before?
honghaiz3
2016/10/20 23:47:58
It is logical to include this although it does not
| |
1582 return false; | 1580 return false; |
1583 } | 1581 } |
1584 | 1582 |
1585 int interval = CalculateActiveWritablePingInterval(selected_connection_, now); | 1583 int interval = CalculateActiveWritablePingInterval(premier_connection, now); |
1586 return selected_connection_->last_ping_sent() + interval <= now; | 1584 return premier_connection->last_ping_sent() + interval <= now; |
1585 } | |
1586 | |
1587 Connection* P2PTransportChannel::FindBestPremierConnectionToPing(int64_t now) { | |
1588 // If the selected connection is pingable, select it to ping. | |
1589 if (IsPremierConnectionPingable(selected_connection_, now)) { | |
1590 return selected_connection_; | |
1591 } | |
1592 | |
1593 // Otherwise, find the premier connection that has not been pinged for the | |
1594 // longest time. | |
1595 Connection* oldest_premier_connection = nullptr; | |
1596 for (auto kv : premier_connection_by_network_name_) { | |
1597 Connection* conn = kv.second; | |
1598 if (conn == nullptr || conn == selected_connection_) { | |
1599 continue; | |
1600 } | |
1601 if (IsPremierConnectionPingable(conn, now) && | |
1602 (!oldest_premier_connection || | |
1603 conn->last_ping_sent() < | |
1604 oldest_premier_connection->last_ping_sent())) { | |
1605 oldest_premier_connection = conn; | |
1606 } | |
1607 } | |
1608 return oldest_premier_connection; | |
1587 } | 1609 } |
1588 | 1610 |
1589 int P2PTransportChannel::CalculateActiveWritablePingInterval( | 1611 int P2PTransportChannel::CalculateActiveWritablePingInterval( |
1590 const Connection* conn, | 1612 const Connection* conn, |
1591 int64_t now) const { | 1613 int64_t now) const { |
1592 // Ping each connection at a higher rate at least | 1614 // Ping each connection at a higher rate at least |
1593 // MIN_PINGS_AT_WEAK_PING_INTERVAL times. | 1615 // MIN_PINGS_AT_WEAK_PING_INTERVAL times. |
1594 if (conn->num_pings_sent() < MIN_PINGS_AT_WEAK_PING_INTERVAL) { | 1616 if (conn->num_pings_sent() < MIN_PINGS_AT_WEAK_PING_INTERVAL) { |
1595 return weak_ping_interval_; | 1617 return weak_ping_interval_; |
1596 } | 1618 } |
1597 | 1619 |
1598 int stable_interval = config_.stable_writable_connection_ping_interval; | 1620 int stable_interval = config_.stable_writable_connection_ping_interval; |
1599 int stablizing_interval = | 1621 int stablizing_interval = |
1600 std::min(stable_interval, STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL); | 1622 std::min(stable_interval, STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL); |
1601 | 1623 // If the channel is weak or the connection is not stable yet, use the |
1602 return conn->stable(now) ? stable_interval : stablizing_interval; | 1624 // stablizing_interval. |
1625 return (!weak() && conn->stable(now)) ? stable_interval : stablizing_interval; | |
Taylor Brandstetter
2016/10/04 02:08:09
So this is now the "stabilizing or weak" interval?
honghaiz3
2016/10/20 23:47:58
Changed to weak_or_stablizing_interval.
| |
1603 } | 1626 } |
1604 | 1627 |
1605 // Returns the next pingable connection to ping. This will be the oldest | 1628 // Returns the next pingable connection to ping. This will be the oldest |
1606 // pingable connection unless we have a connected, writable connection that is | 1629 // pingable connection unless we have a connected, writable connection that is |
1607 // past the writable ping interval. When reconnecting a TCP | 1630 // past the writable ping interval. When reconnecting a TCP |
1608 // connection, the selected connection is disconnected, although still WRITABLE | 1631 // connection, the selected connection is disconnected, although still WRITABLE |
1609 // while reconnecting. The newly created connection should be selected as the | 1632 // while reconnecting. The newly created connection should be selected as the |
1610 // ping target to become writable instead. See the big comment in | 1633 // ping target to become writable instead. See the big comment in |
1611 // CompareConnectionStates. | 1634 // CompareConnectionStates. |
1612 Connection* P2PTransportChannel::FindNextPingableConnection() { | 1635 Connection* P2PTransportChannel::FindNextPingableConnection() { |
1613 int64_t now = rtc::TimeMillis(); | 1636 int64_t now = rtc::TimeMillis(); |
1614 Connection* conn_to_ping = nullptr; | 1637 Connection* conn_to_ping = FindBestPremierConnectionToPing(now); |
1615 if (IsSelectedConnectionPingable(now)) { | 1638 if (!conn_to_ping) { |
1616 conn_to_ping = selected_connection_; | |
1617 } else { | |
1618 conn_to_ping = FindConnectionToPing(now); | 1639 conn_to_ping = FindConnectionToPing(now); |
1619 } | 1640 } |
1620 return conn_to_ping; | 1641 return conn_to_ping; |
1621 } | 1642 } |
1622 | 1643 |
1623 void P2PTransportChannel::MarkConnectionPinged(Connection* conn) { | 1644 void P2PTransportChannel::MarkConnectionPinged(Connection* conn) { |
1624 if (conn && pinged_connections_.insert(conn).second) { | 1645 if (conn && pinged_connections_.insert(conn).second) { |
1625 unpinged_connections_.erase(conn); | 1646 unpinged_connections_.erase(conn); |
1626 } | 1647 } |
1627 } | 1648 } |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1721 // Note: the previous selected_connection_ may be destroyed by now, so don't | 1742 // Note: the previous selected_connection_ may be destroyed by now, so don't |
1722 // use it. | 1743 // use it. |
1723 | 1744 |
1724 // Remove this connection from the list. | 1745 // Remove this connection from the list. |
1725 std::vector<Connection*>::iterator iter = | 1746 std::vector<Connection*>::iterator iter = |
1726 std::find(connections_.begin(), connections_.end(), connection); | 1747 std::find(connections_.begin(), connections_.end(), connection); |
1727 ASSERT(iter != connections_.end()); | 1748 ASSERT(iter != connections_.end()); |
1728 pinged_connections_.erase(*iter); | 1749 pinged_connections_.erase(*iter); |
1729 unpinged_connections_.erase(*iter); | 1750 unpinged_connections_.erase(*iter); |
1730 connections_.erase(iter); | 1751 connections_.erase(iter); |
1752 for (auto kv : premier_connection_by_network_name_) { | |
1753 if (kv.second == connection) { | |
1754 kv.second = nullptr; | |
1755 } | |
1756 } | |
1731 | 1757 |
1732 LOG_J(LS_INFO, this) << "Removed connection (" | 1758 LOG_J(LS_INFO, this) << "Removed connection " << std::hex << connection |
Taylor Brandstetter
2016/10/04 02:08:10
Why not log connection->ToString()?
honghaiz3
2016/10/20 23:47:58
connection->ToString() needs to access the members
Taylor Brandstetter
2016/10/21 20:18:49
Does that risk really exist? I thought a Port is o
honghaiz3
2016/10/21 21:27:26
It probably does not although it would require car
| |
1733 << static_cast<int>(connections_.size()) << " remaining)"; | 1759 << std::dec << " (" |
1760 << static_cast<int>(connections_.size()) | |
1761 << " remaining)"; | |
1734 | 1762 |
1735 // If this is currently the selected connection, then we need to pick a new | 1763 // If this is currently the selected connection, then we need to pick a new |
1736 // one. The call to SortConnectionsAndUpdateState will pick a new one. It | 1764 // one. The call to SortConnectionsAndUpdateState will pick a new one. It |
1737 // looks at the current selected connection in order to avoid switching | 1765 // looks at the current selected connection in order to avoid switching |
1738 // between fairly similar ones. Since this connection is no longer an option, | 1766 // between fairly similar ones. Since this connection is no longer an option, |
1739 // we can just set selected to nullptr and re-choose a best assuming that | 1767 // we can just set selected to nullptr and re-choose a best assuming that |
1740 // there was no selected connection. | 1768 // there was no selected connection. |
1741 if (selected_connection_ == connection) { | 1769 if (selected_connection_ == connection) { |
1742 LOG(LS_INFO) << "Selected connection destroyed. Will choose a new one."; | 1770 LOG(LS_INFO) << "Selected connection destroyed. Will choose a new one."; |
1743 SwitchSelectedConnection(nullptr); | 1771 SwitchSelectedConnection(nullptr); |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1851 } | 1879 } |
1852 | 1880 |
1853 void P2PTransportChannel::OnReadyToSend(Connection* connection) { | 1881 void P2PTransportChannel::OnReadyToSend(Connection* connection) { |
1854 if (connection == selected_connection_ && writable()) { | 1882 if (connection == selected_connection_ && writable()) { |
1855 SignalReadyToSend(this); | 1883 SignalReadyToSend(this); |
1856 } | 1884 } |
1857 } | 1885 } |
1858 | 1886 |
1859 // Find "triggered checks". We ping first those connections that have | 1887 // Find "triggered checks". We ping first those connections that have |
1860 // received a ping but have not sent a ping since receiving it | 1888 // received a ping but have not sent a ping since receiving it |
1861 // (last_received_ping > last_sent_ping). But we shouldn't do | 1889 // (last_ping_received > last_ping_sent). But we shouldn't do |
1862 // triggered checks if the connection is already writable. | 1890 // triggered checks if the connection is already writable. |
1863 Connection* P2PTransportChannel::FindOldestConnectionNeedingTriggeredCheck( | 1891 Connection* P2PTransportChannel::FindOldestConnectionNeedingTriggeredCheck( |
1864 int64_t now) { | 1892 int64_t now) { |
1865 Connection* oldest_needing_triggered_check = nullptr; | 1893 Connection* oldest_needing_triggered_check = nullptr; |
1866 for (auto conn : connections_) { | 1894 for (auto conn : connections_) { |
1867 if (!IsPingable(conn, now)) { | 1895 if (!IsPingable(conn, now)) { |
1868 continue; | 1896 continue; |
1869 } | 1897 } |
1870 bool needs_triggered_check = | 1898 bool needs_triggered_check = |
1871 (!conn->writable() && | 1899 (!conn->writable() && |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1967 | 1995 |
1968 // During the initial state when nothing has been pinged yet, return the first | 1996 // During the initial state when nothing has been pinged yet, return the first |
1969 // one in the ordered |connections_|. | 1997 // one in the ordered |connections_|. |
1970 return *(std::find_if(connections_.begin(), connections_.end(), | 1998 return *(std::find_if(connections_.begin(), connections_.end(), |
1971 [conn1, conn2](Connection* conn) { | 1999 [conn1, conn2](Connection* conn) { |
1972 return conn == conn1 || conn == conn2; | 2000 return conn == conn1 || conn == conn2; |
1973 })); | 2001 })); |
1974 } | 2002 } |
1975 | 2003 |
1976 } // namespace cricket | 2004 } // namespace cricket |
OLD | NEW |