| 153 | } |
| 154 | |
| 155 | void NodeTable::doDiscover(NodeID _node, unsigned _round, shared_ptr<set<shared_ptr<NodeEntry>>> _tried) |
| 156 | { |
| 157 | // NOTE: ONLY called by doDiscovery! |
| 158 | |
| 159 | if (!m_socketPointer->isOpen()) |
| 160 | return; |
| 161 | |
| 162 | if (_round == s_maxSteps) |
| 163 | { |
| 164 | clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds."; |
| 165 | doDiscovery(); |
| 166 | return; |
| 167 | } |
| 168 | else if (!_round && !_tried) |
| 169 | // initialized _tried on first round |
| 170 | _tried = make_shared<set<shared_ptr<NodeEntry>>>(); |
| 171 | |
| 172 | auto nearest = nearestNodeEntries(_node); |
| 173 | list<shared_ptr<NodeEntry>> tried; |
| 174 | for (unsigned i = 0; i < nearest.size() && tried.size() < s_alpha; i++) |
| 175 | if (!_tried->count(nearest[i])) |
| 176 | { |
| 177 | auto r = nearest[i]; |
| 178 | tried.push_back(r); |
| 179 | FindNode p(r->endpoint, _node); |
| 180 | p.sign(m_secret); |
| 181 | DEV_GUARDED(x_findNodeTimeout) |
| 182 | m_findNodeTimeout.push_back(make_pair(r->id, chrono::steady_clock::now())); |
| 183 | m_socketPointer->send(p); |
| 184 | } |
| 185 | |
| 186 | if (tried.empty()) |
| 187 | { |
| 188 | clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds."; |
| 189 | doDiscovery(); |
| 190 | return; |
| 191 | } |
| 192 | |
| 193 | while (!tried.empty()) |
| 194 | { |
| 195 | _tried->insert(tried.front()); |
| 196 | tried.pop_front(); |
| 197 | } |
| 198 | |
| 199 | m_timers.schedule(c_reqTimeout.count() * 2, [this, _node, _round, _tried](boost::system::error_code const& _ec) |
| 200 | { |
| 201 | if (_ec) |
| 202 | clog(NodeTableMessageDetail) << "Discovery timer was probably cancelled: " << _ec.value() << _ec.message(); |
| 203 | |
| 204 | if (_ec.value() == boost::asio::error::operation_aborted || m_timers.isStopped()) |
| 205 | return; |
| 206 | |
| 207 | // error::operation_aborted means that the timer was probably aborted. |
| 208 | // It usually happens when "this" object is deallocated, in which case |
| 209 | // subsequent call to doDiscover() would cause a crash. We can not rely on |
| 210 | // m_timers.isStopped(), because "this" pointer was captured by the lambda, |
| 211 | // and therefore, in case of deallocation m_timers object no longer exists. |
| 212 |
nothing calls this directly
no test coverage detected