~ubuntu-branches/ubuntu/oneiric/libtorrent/oneiric

« back to all changes in this revision

Viewing changes to .pc/libtorrent-0.12.6-ipv6-07.patch/src/torrent/peer/peer_list.cc

  • Committer: Bazaar Package Importer
  • Author(s): Rogério Brito
  • Date: 2011-03-20 01:06:18 UTC
  • mfrom: (1.1.13 upstream) (4.1.9 sid)
  • Revision ID: james.westby@ubuntu.com-20110320010618-g3wyylccqzqko73c
Tags: 0.12.7-5
* Use Steinar's "real" patch for IPv6. Addresses #490277, #618275,
  and Closes: #617791.
* Adapt libtorrent-0.12.6-ipv6-07.patch. It FTBFS otherwise.
* Add proper attibution to the IPv6 patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// libTorrent - BitTorrent library
 
2
// Copyright (C) 2005-2007, Jari Sundell
 
3
//
 
4
// This program is free software; you can redistribute it and/or modify
 
5
// it under the terms of the GNU General Public License as published by
 
6
// the Free Software Foundation; either version 2 of the License, or
 
7
// (at your option) any later version.
 
8
// 
 
9
// This program is distributed in the hope that it will be useful,
 
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
// GNU General Public License for more details.
 
13
// 
 
14
// You should have received a copy of the GNU General Public License
 
15
// along with this program; if not, write to the Free Software
 
16
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
//
 
18
// In addition, as a special exception, the copyright holders give
 
19
// permission to link the code of portions of this program with the
 
20
// OpenSSL library under certain conditions as described in each
 
21
// individual source file, and distribute linked combinations
 
22
// including the two.
 
23
//
 
24
// You must obey the GNU General Public License in all respects for
 
25
// all of the code used other than OpenSSL.  If you modify file(s)
 
26
// with this exception, you may extend this exception to your version
 
27
// of the file(s), but you are not obligated to do so.  If you do not
 
28
// wish to do so, delete this exception statement from your version.
 
29
// If you delete this exception statement from all source files in the
 
30
// program, then also delete it here.
 
31
//
 
32
// Contact:  Jari Sundell <jaris@ifi.uio.no>
 
33
//
 
34
//           Skomakerveien 33
 
35
//           3185 Skoppum, NORWAY
 
36
 
 
37
#include "config.h"
 
38
 
 
39
#include <algorithm>
 
40
#include <functional>
 
41
#include <rak/functional.h>
 
42
#include <rak/socket_address.h>
 
43
 
 
44
#include "download/available_list.h"
 
45
#include "torrent/peer/client_list.h"
 
46
 
 
47
#include "exceptions.h"
 
48
#include "globals.h"
 
49
#include "manager.h"
 
50
#include "peer_info.h"
 
51
#include "peer_list.h"
 
52
 
 
53
namespace torrent {
 
54
 
 
55
bool
 
56
socket_address_less(const sockaddr* s1, const sockaddr* s2) {
 
57
  const rak::socket_address* sa1 = rak::socket_address::cast_from(s1);
 
58
  const rak::socket_address* sa2 = rak::socket_address::cast_from(s2);
 
59
 
 
60
  if (sa1->family() != sa2->family())
 
61
    return sa1->family() < sa2->family();
 
62
 
 
63
  else if (sa1->family() == rak::socket_address::af_inet)
 
64
    // Sort by hardware byte order to ensure proper ordering for
 
65
    // humans.
 
66
    return sa1->sa_inet()->address_h() < sa2->sa_inet()->address_h();
 
67
 
 
68
  else
 
69
    // When we implement INET6 handling, embed the ipv4 address in
 
70
    // the ipv6 address.
 
71
    throw internal_error("socket_address_key(...) tried to compare an invalid family type.");
 
72
}
 
73
 
 
74
inline bool
 
75
socket_address_key::is_comparable(const sockaddr* sa) {
 
76
  return rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet;
 
77
}
 
78
 
 
79
struct peer_list_equal_port : public std::binary_function<PeerList::reference, uint16_t, bool> {
 
80
  bool operator () (PeerList::reference p, uint16_t port) {
 
81
    return rak::socket_address::cast_from(p.second->socket_address())->port() == port;
 
82
  }
 
83
};
 
84
 
 
85
PeerList::PeerList() :
 
86
  m_availableList(new AvailableList) {
 
87
}
 
88
 
 
89
PeerList::~PeerList() {
 
90
  std::for_each(begin(), end(), rak::on(rak::mem_ref(&value_type::second), rak::call_delete<PeerInfo>()));
 
91
  base_type::clear();
 
92
 
 
93
  delete m_availableList;
 
94
}
 
95
 
 
96
PeerInfo*
 
97
PeerList::insert_address(const sockaddr* sa, int flags) {
 
98
  if (!socket_address_key::is_comparable(sa))
 
99
    return NULL;
 
100
 
 
101
  range_type range = base_type::equal_range(sa);
 
102
 
 
103
  // Do some special handling if we got a new port number but the
 
104
  // address was present.
 
105
  //
 
106
  // What we do depends on the flags, but for now just allow one
 
107
  // PeerInfo per address key and do nothing.
 
108
  if (range.first != range.second)
 
109
    return NULL;
 
110
 
 
111
  const rak::socket_address* address = rak::socket_address::cast_from(sa);
 
112
 
 
113
  PeerInfo* peerInfo = new PeerInfo(sa);
 
114
  peerInfo->set_listen_port(address->port());
 
115
  
 
116
  manager->client_list()->retrieve_unknown(&peerInfo->mutable_client_info());
 
117
 
 
118
  base_type::insert(range.second, value_type(socket_address_key(peerInfo->socket_address()), peerInfo));
 
119
 
 
120
  if (flags & address_available && peerInfo->listen_port() != 0)
 
121
    m_availableList->push_back(address);
 
122
 
 
123
  return peerInfo;
 
124
}
 
125
 
 
126
inline bool
 
127
socket_address_less_rak(const rak::socket_address& s1, const rak::socket_address& s2) {
 
128
  return socket_address_less(s1.c_sockaddr(), s2.c_sockaddr());
 
129
}
 
130
 
 
131
uint32_t
 
132
PeerList::insert_available(const void* al) {
 
133
  uint32_t inserted = 0;
 
134
  const AddressList* addressList = static_cast<const AddressList*>(al);
 
135
 
 
136
  if (m_availableList->size() + addressList->size() > m_availableList->capacity())
 
137
    m_availableList->reserve(m_availableList->size() + addressList->size() + 128);
 
138
 
 
139
  // Optimize this so that we don't traverse the tree for every
 
140
  // insert, since we know 'al' is sorted.
 
141
 
 
142
  AddressList::const_iterator itr   = addressList->begin();
 
143
  AddressList::const_iterator last  = addressList->end();
 
144
  AvailableList::const_iterator availItr  = m_availableList->begin();
 
145
  AvailableList::const_iterator availLast = m_availableList->end();
 
146
 
 
147
  for (; itr != last; itr++) {
 
148
    if (!socket_address_key::is_comparable(itr->c_sockaddr()) || itr->port() == 0)
 
149
      continue;
 
150
 
 
151
    availItr = std::find_if(availItr, availLast, rak::bind2nd(std::ptr_fun(&socket_address_less_rak), *itr));
 
152
 
 
153
    if (availItr != availLast && !socket_address_less(availItr->c_sockaddr(), itr->c_sockaddr())) {
 
154
      // The address is already in m_availableList, so don't bother
 
155
      // going further.
 
156
      continue;
 
157
    }
 
158
 
 
159
    // Check if the peerinfo exists, if it does, check if we would
 
160
    // ever want to connect. Just update the timer for the last
 
161
    // availability notice if the peer isn't really ideal, but might
 
162
    // be used in an emergency.
 
163
    range_type range = base_type::equal_range(itr->c_sockaddr());
 
164
 
 
165
    if (range.first != range.second) {
 
166
      // Add some logic here to select the best PeerInfo, but for now
 
167
      // just assume the first one is the only one that exists.
 
168
      PeerInfo* peerInfo = range.first->second;
 
169
 
 
170
      if (peerInfo->listen_port() == 0)
 
171
        peerInfo->set_port(itr->port());
 
172
 
 
173
      if (peerInfo->connection() != NULL ||
 
174
          peerInfo->last_handshake() + 600 > (uint32_t)cachedTime.seconds())
 
175
        continue;
 
176
 
 
177
      // If the peer has sent us bad chunks or we just connected or
 
178
      // tried to do so a few minutes ago, only update its
 
179
      // availability timer.
 
180
    }
 
181
 
 
182
    // Should we perhaps add to available list even though we don't
 
183
    // want the peer, just to ensure we don't need to search for the
 
184
    // PeerInfo every time it gets reported. Though I'd assume it
 
185
    // won't happen often enough to be worth it.
 
186
 
 
187
    inserted++;
 
188
    m_availableList->push_back(&*itr);
 
189
  }
 
190
 
 
191
  return inserted;
 
192
}
 
193
 
 
194
uint32_t
 
195
PeerList::available_list_size() const {
 
196
  return m_availableList->size();
 
197
}
 
198
 
 
199
PeerInfo*
 
200
PeerList::connected(const sockaddr* sa, int flags) {
 
201
  if (!socket_address_key::is_comparable(sa))
 
202
    return NULL;
 
203
 
 
204
  PeerInfo* peerInfo;
 
205
  const rak::socket_address* address = rak::socket_address::cast_from(sa);
 
206
 
 
207
  range_type range = base_type::equal_range(sa);
 
208
 
 
209
  if (range.first == range.second) {
 
210
    // Create a new entry.
 
211
    peerInfo = new PeerInfo(sa);
 
212
 
 
213
    base_type::insert(range.second, value_type(socket_address_key(peerInfo->socket_address()), peerInfo));
 
214
 
 
215
  } else if (!range.first->second->is_connected()) {
 
216
    // Use an old entry.
 
217
    peerInfo = range.first->second;
 
218
    peerInfo->set_port(address->port());
 
219
 
 
220
  } else {
 
221
    // Make sure we don't end up throwing away the port the host is
 
222
    // actually listening on, when there may be several simultaneous
 
223
    // connection attempts to/from different ports.
 
224
    //
 
225
    // This also ensure we can connect to peers running on the same
 
226
    // host as the tracker.
 
227
    if (flags & connect_keep_handshakes &&
 
228
        range.first->second->is_handshake() &&
 
229
        rak::socket_address::cast_from(range.first->second->socket_address())->port() != address->port())
 
230
      m_availableList->buffer()->push_back(*address);
 
231
 
 
232
    return NULL;
 
233
  }
 
234
 
 
235
  if (flags & connect_filter_recent &&
 
236
      peerInfo->last_handshake() + 600 > (uint32_t)cachedTime.seconds())
 
237
    return NULL;
 
238
 
 
239
  if (!(flags & connect_incoming))
 
240
    peerInfo->set_listen_port(address->port());
 
241
 
 
242
  if (flags & connect_incoming)
 
243
    peerInfo->set_flags(PeerInfo::flag_incoming);
 
244
  else
 
245
    peerInfo->unset_flags(PeerInfo::flag_incoming);
 
246
 
 
247
  peerInfo->set_flags(PeerInfo::flag_connected);
 
248
  peerInfo->set_last_handshake(cachedTime.seconds());
 
249
 
 
250
  return peerInfo;
 
251
}
 
252
 
 
253
// Make sure we properly clear port when disconnecting.
 
254
 
 
255
void
 
256
PeerList::disconnected(PeerInfo* p, int flags) {
 
257
  range_type range = base_type::equal_range(p->socket_address());
 
258
  
 
259
  iterator itr = std::find_if(range.first, range.second, rak::equal(p, rak::mem_ref(&value_type::second)));
 
260
 
 
261
  if (itr == range.second) {
 
262
    if (std::find_if(base_type::begin(), base_type::end(), rak::equal(p, rak::mem_ref(&value_type::second))) == base_type::end())
 
263
      throw internal_error("PeerList::disconnected(...) itr == range.second, doesn't exist.");
 
264
    else
 
265
      throw internal_error("PeerList::disconnected(...) itr == range.second, not in the range.");
 
266
  }
 
267
  
 
268
  disconnected(itr, flags);
 
269
}
 
270
 
 
271
PeerList::iterator
 
272
PeerList::disconnected(iterator itr, int flags) {
 
273
  if (itr == base_type::end())
 
274
    throw internal_error("PeerList::disconnected(...) itr == end().");
 
275
 
 
276
  if (!itr->second->is_connected())
 
277
    throw internal_error("PeerList::disconnected(...) !itr->is_connected().");
 
278
 
 
279
  itr->second->unset_flags(PeerInfo::flag_connected);
 
280
 
 
281
  // Replace the socket address port with the listening port so that
 
282
  // future outgoing connections will connect to the right port.
 
283
  itr->second->set_port(0);
 
284
 
 
285
  if (flags & disconnect_set_time)
 
286
    itr->second->set_last_connection(cachedTime.seconds());
 
287
 
 
288
  if (flags & disconnect_available && itr->second->listen_port() != 0)
 
289
    m_availableList->push_back(rak::socket_address::cast_from(itr->second->socket_address()));
 
290
 
 
291
  // Do magic to get rid of unneeded entries.
 
292
  return ++itr;
 
293
}
 
294
 
 
295
uint32_t
 
296
PeerList::cull_peers(int flags) {
 
297
  uint32_t counter = 0;
 
298
  uint32_t timer;
 
299
 
 
300
  if (flags & cull_old)
 
301
    timer = cachedTime.seconds() - 24 * 60 * 60;
 
302
  else
 
303
    timer = 0;
 
304
 
 
305
  for (iterator itr = base_type::begin(); itr != base_type::end(); ) {
 
306
    if (itr->second->is_connected() ||
 
307
        itr->second->transfer_counter() != 0 ||
 
308
        itr->second->last_connection() >= timer ||
 
309
 
 
310
        (flags & cull_keep_interesting && 
 
311
         (itr->second->failed_counter() != 0 || itr->second->is_blocked()))) {
 
312
      itr++;
 
313
      continue;
 
314
    }
 
315
 
 
316
    // The key is a pointer to a member in the value, although the key
 
317
    // shouldn't actually be used in erase (I think), just ot be safe
 
318
    // we delete it after erase.
 
319
    iterator tmp = itr++;
 
320
    PeerInfo* peerInfo = tmp->second;
 
321
 
 
322
    base_type::erase(tmp);
 
323
    delete peerInfo;
 
324
 
 
325
    counter++;
 
326
  }
 
327
 
 
328
  return counter;
 
329
}
 
330
 
 
331
}