| 1149 | |
| 1150 | template<typename Filter> |
| 1151 | std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (Filter filter) const |
| 1152 | { |
| 1153 | if (m_Peers.empty()) return nullptr; |
| 1154 | auto ts = i2p::util::GetSecondsSinceEpoch (); |
| 1155 | bool found = false; |
| 1156 | i2p::data::IdentHash ident; |
| 1157 | { |
| 1158 | uint16_t inds[3]; |
| 1159 | RAND_bytes ((uint8_t *)inds, sizeof (inds)); |
| 1160 | std::lock_guard<std::mutex> l(m_PeersMutex); |
| 1161 | auto count = m_Peers.size (); |
| 1162 | if(count == 0) return nullptr; |
| 1163 | inds[0] %= count; |
| 1164 | auto it = m_Peers.begin (); |
| 1165 | std::advance (it, inds[0]); |
| 1166 | // try random peer |
| 1167 | if (it != m_Peers.end () && filter (it->second)) |
| 1168 | { |
| 1169 | ident = it->first; |
| 1170 | found = true; |
| 1171 | } |
| 1172 | else |
| 1173 | { |
| 1174 | // try some peers around |
| 1175 | auto it1 = m_Peers.begin (); |
| 1176 | if (inds[0]) |
| 1177 | { |
| 1178 | // before |
| 1179 | inds[1] %= inds[0]; |
| 1180 | std::advance (it1, (inds[1] + inds[0])/2); |
| 1181 | } |
| 1182 | else |
| 1183 | it1 = it; |
| 1184 | auto it2 = it; |
| 1185 | if (inds[0] < m_Peers.size () - 1) |
| 1186 | { |
| 1187 | // after |
| 1188 | inds[2] %= (m_Peers.size () - 1 - inds[0]); inds[2] /= 2; |
| 1189 | std::advance (it2, inds[2]); |
| 1190 | } |
| 1191 | // it1 - from, it2 - to |
| 1192 | it = it1; |
| 1193 | while (it != it2 && it != m_Peers.end ()) |
| 1194 | { |
| 1195 | if (ts > it->second->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL && |
| 1196 | filter (it->second)) |
| 1197 | { |
| 1198 | ident = it->first; |
| 1199 | it->second->lastSelectionTime = ts; |
| 1200 | found = true; |
| 1201 | break; |
| 1202 | } |
| 1203 | it++; |
| 1204 | } |
| 1205 | if (!found) |
| 1206 | { |
| 1207 | // still not found, try from the beginning |
| 1208 | it = m_Peers.begin (); |
no test coverage detected