Coverage Report

Created: 2025-11-09 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libtorrent/src/kademlia/find_data.cpp
Line
Count
Source
1
/*
2
3
Copyright (c) 2006, Daniel Wallin
4
Copyright (c) 2006, 2008-2010, 2013-2017, 2019, Arvid Norberg
5
Copyright (c) 2015, Thomas Yuan
6
Copyright (c) 2016-2017, Alden Torres
7
Copyright (c) 2017, Pavel Pimenov
8
All rights reserved.
9
10
Redistribution and use in source and binary forms, with or without
11
modification, are permitted provided that the following conditions
12
are met:
13
14
    * Redistributions of source code must retain the above copyright
15
      notice, this list of conditions and the following disclaimer.
16
    * Redistributions in binary form must reproduce the above copyright
17
      notice, this list of conditions and the following disclaimer in
18
      the documentation and/or other materials provided with the distribution.
19
    * Neither the name of the author nor the names of its
20
      contributors may be used to endorse or promote products derived
21
      from this software without specific prior written permission.
22
23
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
POSSIBILITY OF SUCH DAMAGE.
34
35
*/
36
37
#include <libtorrent/kademlia/find_data.hpp>
38
#include <libtorrent/kademlia/node.hpp>
39
#include <libtorrent/kademlia/dht_observer.hpp>
40
#include <libtorrent/io.hpp>
41
#include <libtorrent/socket.hpp>
42
#include <libtorrent/socket_io.hpp>
43
44
#ifndef TORRENT_DISABLE_LOGGING
45
#include <libtorrent/hex.hpp> // to_hex
46
#endif
47
48
namespace libtorrent { namespace dht {
49
50
void find_data_observer::reply(msg const& m)
51
0
{
52
0
  bdecode_node const r = m.message.dict_find_dict("r");
53
0
  if (!r)
54
0
  {
55
#ifndef TORRENT_DISABLE_LOGGING
56
    get_observer()->log(dht_logger::traversal, "[%u] missing response dict"
57
      , algorithm()->id());
58
#endif
59
0
    timeout();
60
0
    return;
61
0
  }
62
63
0
  bdecode_node const id = r.dict_find_string("id");
64
0
  if (!id || id.string_length() != 20)
65
0
  {
66
#ifndef TORRENT_DISABLE_LOGGING
67
    get_observer()->log(dht_logger::traversal, "[%u] invalid id in response"
68
      , algorithm()->id());
69
#endif
70
0
    timeout();
71
0
    return;
72
0
  }
73
0
  bdecode_node const token = r.dict_find_string("token");
74
0
  if (token)
75
0
  {
76
0
    static_cast<find_data*>(algorithm())->got_write_token(
77
0
      node_id(id.string_ptr()), token.string_value().to_string());
78
0
  }
79
80
0
  traversal_observer::reply(m);
81
0
  done();
82
0
}
83
84
find_data::find_data(
85
  node& dht_node
86
  , node_id const& target
87
  , nodes_callback ncallback)
88
0
  : traversal_algorithm(dht_node, target)
89
0
  , m_nodes_callback(std::move(ncallback))
90
0
  , m_done(false)
91
0
{
92
0
}
93
94
void find_data::start()
95
0
{
96
  // if the user didn't add seed-nodes manually, grab k (bucket size)
97
  // nodes from routing table.
98
0
  if (m_results.empty())
99
0
  {
100
0
    std::vector<node_entry> const nodes = m_node.m_table.find_node(
101
0
      target(), routing_table::include_failed);
102
103
0
    for (auto const& n : nodes)
104
0
    {
105
0
      add_entry(n.id, n.ep(), observer::flag_initial);
106
0
    }
107
0
  }
108
109
0
  traversal_algorithm::start();
110
0
}
111
112
void find_data::got_write_token(node_id const& n, std::string write_token)
113
0
{
114
#ifndef TORRENT_DISABLE_LOGGING
115
  auto logger = get_node().observer();
116
  if (logger != nullptr && logger->should_log(dht_logger::traversal))
117
  {
118
    logger->log(dht_logger::traversal
119
      , "[%u] adding write token '%s' under id '%s'"
120
      , id(), aux::to_hex(write_token).c_str()
121
      , aux::to_hex(n).c_str());
122
  }
123
#endif
124
0
  m_write_tokens[n] = std::move(write_token);
125
0
}
126
127
observer_ptr find_data::new_observer(udp::endpoint const& ep
128
  , node_id const& id)
129
0
{
130
0
  auto o = m_node.m_rpc.allocate_observer<find_data_observer>(self(), ep, id);
131
0
#if TORRENT_USE_ASSERTS
132
0
  if (o) o->m_in_constructor = false;
133
0
#endif
134
0
  return o;
135
0
}
136
137
0
char const* find_data::name() const { return "find_data"; }
138
139
void find_data::done()
140
0
{
141
0
  m_done = true;
142
143
#ifndef TORRENT_DISABLE_LOGGING
144
  auto logger = get_node().observer();
145
  if (logger != nullptr)
146
  {
147
    logger->log(dht_logger::traversal, "[%u] %s DONE"
148
      , id(), name());
149
  }
150
#endif
151
152
0
  std::vector<std::pair<node_entry, std::string>> results;
153
0
  int num_results = m_node.m_table.bucket_size();
154
0
  for (auto i = m_results.begin()
155
0
    , end(m_results.end()); i != end && num_results > 0; ++i)
156
0
  {
157
0
    observer_ptr const& o = *i;
158
0
    if (!(o->flags & observer::flag_alive))
159
0
    {
160
#ifndef TORRENT_DISABLE_LOGGING
161
      if (logger != nullptr && logger->should_log(dht_logger::traversal))
162
      {
163
        logger->log(dht_logger::traversal, "[%u] not alive: %s"
164
          , id(), print_endpoint(o->target_ep()).c_str());
165
      }
166
#endif
167
0
      continue;
168
0
    }
169
0
    auto j = m_write_tokens.find(o->id());
170
0
    if (j == m_write_tokens.end())
171
0
    {
172
#ifndef TORRENT_DISABLE_LOGGING
173
      if (logger != nullptr && logger->should_log(dht_logger::traversal))
174
      {
175
        logger->log(dht_logger::traversal, "[%u] no write token: %s"
176
          , id(), print_endpoint(o->target_ep()).c_str());
177
      }
178
#endif
179
0
      continue;
180
0
    }
181
0
    results.emplace_back(node_entry(o->id(), o->target_ep()), j->second);
182
#ifndef TORRENT_DISABLE_LOGGING
183
    if (logger != nullptr && logger->should_log(dht_logger::traversal))
184
    {
185
      logger->log(dht_logger::traversal, "[%u] %s"
186
        , id(), print_endpoint(o->target_ep()).c_str());
187
    }
188
#endif
189
0
    --num_results;
190
0
  }
191
192
0
  if (m_nodes_callback) m_nodes_callback(results);
193
194
0
  traversal_algorithm::done();
195
0
}
196
197
} } // namespace libtorrent::dht