~ubuntu-branches/debian/experimental/libtorrent/experimental

« back to all changes in this revision

Viewing changes to src/torrent/peer_list.cc

  • Committer: Bazaar Package Importer
  • Author(s): Jose Luis Rivas
  • Date: 2007-03-31 10:31:05 UTC
  • mto: (4.1.4 gutsy) (6.2.1 squeeze) (1.3.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 6.
  • Revision ID: james.westby@ubuntu.com-20070331103105-jzpp1rml6ud0ff75
Tags: upstream-0.11.4
ImportĀ upstreamĀ versionĀ 0.11.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// libTorrent - BitTorrent library
2
 
// Copyright (C) 2005-2006, 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
 
 
46
 
#include "exceptions.h"
47
 
#include "globals.h"
48
 
#include "peer_info.h"
49
 
#include "peer_list.h"
50
 
 
51
 
namespace torrent {
52
 
 
53
 
bool
54
 
socket_address_key::operator < (const socket_address_key& sa) const {
55
 
  const rak::socket_address* sa1 = rak::socket_address::cast_from(m_sockaddr);
56
 
  const rak::socket_address* sa2 = rak::socket_address::cast_from(sa.m_sockaddr);
57
 
 
58
 
  if (sa1->family() != sa2->family())
59
 
    return sa1->family() > sa2->family();
60
 
 
61
 
  else if (sa1->family() == rak::socket_address::af_inet)
62
 
    // Sort by hardware byte order to ensure proper ordering for
63
 
    // humans.
64
 
    return sa1->sa_inet()->address_h() < sa2->sa_inet()->address_h();
65
 
 
66
 
  else
67
 
    // When we implement INET6 handling, embed the ipv4 address in
68
 
    // the ipv6 address.
69
 
    throw internal_error("socket_address_key(...) tried to compare an invalid family type.");
70
 
}
71
 
 
72
 
struct peer_list_equal_port : public std::binary_function<PeerList::reference, uint16_t, bool> {
73
 
  bool operator () (PeerList::reference p, uint16_t port) {
74
 
    return rak::socket_address::cast_from(p.second->socket_address())->port() == port;
75
 
  }
76
 
};
77
 
 
78
 
PeerList::PeerList() :
79
 
  m_availableList(new AvailableList) {
80
 
}
81
 
 
82
 
PeerList::~PeerList() {
83
 
  std::for_each(begin(), end(), rak::on(rak::mem_ref(&value_type::second), rak::call_delete<PeerInfo>()));
84
 
  base_type::clear();
85
 
 
86
 
  delete m_availableList;
87
 
}
88
 
 
89
 
PeerInfo*
90
 
PeerList::insert_address(const sockaddr* sa, int flags) {
91
 
  range_type range = base_type::equal_range(sa);
92
 
 
93
 
  // Do some special handling if we got a new port number but the
94
 
  // address was present.
95
 
  //
96
 
  // What we do depends on the flags, but for now just allow one
97
 
  // PeerInfo per address key and do nothing.
98
 
  if (range.first != range.second)
99
 
    return NULL;
100
 
 
101
 
  const rak::socket_address* address = rak::socket_address::cast_from(sa);
102
 
 
103
 
  PeerInfo* peerInfo = new PeerInfo(sa);
104
 
  peerInfo->set_listen_port(address->port());
105
 
 
106
 
  base_type::insert(range.second, value_type(socket_address_key(peerInfo->socket_address()), peerInfo));
107
 
 
108
 
  if (flags & address_available && peerInfo->listen_port() != 0)
109
 
    m_availableList->push_back(address);
110
 
 
111
 
  return peerInfo;
112
 
}
113
 
 
114
 
PeerInfo*
115
 
PeerList::connected(const sockaddr* sa, int flags) {
116
 
  PeerInfo* peerInfo;
117
 
  const rak::socket_address* address = rak::socket_address::cast_from(sa);
118
 
 
119
 
  range_type range = base_type::equal_range(sa);
120
 
 
121
 
  if (range.first == range.second) {
122
 
    // Create a new entry.
123
 
    peerInfo = new PeerInfo(sa);
124
 
 
125
 
    base_type::insert(range.second, value_type(socket_address_key(peerInfo->socket_address()), peerInfo));
126
 
 
127
 
  } else if (!range.first->second->is_connected()) {
128
 
    // Use an old entry.
129
 
    peerInfo = range.first->second;
130
 
    peerInfo->set_port(address->port());
131
 
 
132
 
  } else {
133
 
    // Make sure we don't end up throwing away the port the host is
134
 
    // actually listening on, when there may be several simultaneous
135
 
    // connection attempts to/from different ports.
136
 
    //
137
 
    // This also ensure we can connect to peers running on the same
138
 
    // host as the tracker.
139
 
    if (flags & connect_keep_handshakes &&
140
 
        range.first->second->is_handshake() &&
141
 
        rak::socket_address::cast_from(range.first->second->socket_address())->port() != address->port())
142
 
      m_availableList->buffer()->push_back(*address);
143
 
 
144
 
    return NULL;
145
 
  }
146
 
 
147
 
  if (!(flags & connect_incoming))
148
 
    peerInfo->set_listen_port(address->port());
149
 
 
150
 
  if (flags & connect_incoming)
151
 
    peerInfo->set_flags(PeerInfo::flag_incoming);
152
 
  else
153
 
    peerInfo->unset_flags(PeerInfo::flag_incoming);
154
 
 
155
 
  peerInfo->set_flags(PeerInfo::flag_connected);
156
 
  peerInfo->set_last_connection(cachedTime.seconds());
157
 
 
158
 
  return peerInfo;
159
 
}
160
 
 
161
 
// Make sure we properly clear port when disconnecting.
162
 
 
163
 
void
164
 
PeerList::disconnected(PeerInfo* p, int flags) {
165
 
  range_type range = base_type::equal_range(p->socket_address());
166
 
  
167
 
  iterator itr = std::find_if(range.first, range.second, rak::equal(p, rak::mem_ref(&value_type::second)));
168
 
 
169
 
  if (itr == range.second)
170
 
    if (std::find_if(base_type::begin(), base_type::end(), rak::equal(p, rak::mem_ref(&value_type::second))) == base_type::end())
171
 
      throw internal_error("PeerList::disconnected(...) itr == range.second, doesn't exist.");
172
 
    else
173
 
      throw internal_error("PeerList::disconnected(...) itr == range.second, not in the range.");
174
 
  
175
 
  disconnected(itr, flags);
176
 
}
177
 
 
178
 
PeerList::iterator
179
 
PeerList::disconnected(iterator itr, int flags) {
180
 
  if (itr == base_type::end())
181
 
    throw internal_error("PeerList::disconnected(...) itr == end().");
182
 
 
183
 
  if (!itr->second->is_connected())
184
 
    throw internal_error("PeerList::disconnected(...) !itr->is_connected().");
185
 
 
186
 
  itr->second->unset_flags(PeerInfo::flag_connected);
187
 
  itr->second->set_last_connection(cachedTime.seconds());
188
 
 
189
 
  // Replace the socket address port with the listening port so that
190
 
  // future outgoing connections will connect to the right port.
191
 
  itr->second->set_port(0);
192
 
 
193
 
  if (flags & disconnect_available && itr->second->listen_port() != 0)
194
 
    m_availableList->push_back(rak::socket_address::cast_from(itr->second->socket_address()));
195
 
 
196
 
  // Do magic to get rid of unneeded entries.
197
 
  return ++itr;
198
 
}
199
 
 
200
 
uint32_t
201
 
PeerList::cull_peers(int flags) {
202
 
  uint32_t counter = 0;
203
 
  uint32_t timer;
204
 
 
205
 
  if (flags & cull_old)
206
 
    timer = cachedTime.seconds() - 24 * 60 * 60;
207
 
  else
208
 
    timer = 0;
209
 
 
210
 
  for (iterator itr = base_type::begin(); itr != base_type::end(); ) {
211
 
    if (itr->second->is_connected() ||
212
 
        itr->second->transfer_counter() != 0 ||
213
 
        itr->second->last_connection() >= timer ||
214
 
 
215
 
        (flags & cull_keep_interesting && itr->second->failed_counter() != 0)) {
216
 
      itr++;
217
 
      continue;
218
 
    }
219
 
 
220
 
    // The key is a pointer to a member in the value, although the key
221
 
    // shouldn't actually be used in erase (I think), just ot be safe
222
 
    // we delete it after erase.
223
 
    iterator tmp = itr++;
224
 
    PeerInfo* peerInfo = tmp->second;
225
 
 
226
 
    base_type::erase(tmp);
227
 
    delete peerInfo;
228
 
 
229
 
    counter++;
230
 
  }
231
 
 
232
 
  return counter;
233
 
}
234
 
 
235
 
}