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

« back to all changes in this revision

Viewing changes to .pc/561232.patch/src/protocol/handshake_manager.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 <rak/socket_address.h>
 
40
 
 
41
#include "torrent/exceptions.h"
 
42
#include "torrent/error.h"
 
43
#include "download/download_main.h"
 
44
#include "torrent/connection_manager.h"
 
45
#include "torrent/download_info.h"
 
46
#include "torrent/peer/peer_info.h"
 
47
#include "torrent/peer/client_list.h"
 
48
#include "torrent/peer/connection_list.h"
 
49
 
 
50
#include "peer_connection_base.h"
 
51
#include "handshake.h"
 
52
#include "handshake_manager.h"
 
53
 
 
54
#include "manager.h"
 
55
 
 
56
namespace torrent {
 
57
 
 
58
ProtocolExtension HandshakeManager::DefaultExtensions = ProtocolExtension::make_default();
 
59
 
 
60
inline void
 
61
handshake_manager_delete_handshake(Handshake* h) {
 
62
  h->deactivate_connection();
 
63
  h->destroy_connection();
 
64
 
 
65
  delete h;
 
66
}
 
67
 
 
68
HandshakeManager::size_type
 
69
HandshakeManager::size_info(DownloadMain* info) const {
 
70
  return std::count_if(base_type::begin(), base_type::end(), rak::equal(info, std::mem_fun(&Handshake::download)));
 
71
}
 
72
 
 
73
void
 
74
HandshakeManager::clear() {
 
75
  std::for_each(base_type::begin(), base_type::end(), std::ptr_fun(&handshake_manager_delete_handshake));
 
76
  base_type::clear();
 
77
}
 
78
 
 
79
void
 
80
HandshakeManager::erase(Handshake* handshake) {
 
81
  iterator itr = std::find(base_type::begin(), base_type::end(), handshake);
 
82
 
 
83
  if (itr == base_type::end())
 
84
    throw internal_error("HandshakeManager::erase(...) could not find handshake.");
 
85
 
 
86
  base_type::erase(itr);
 
87
}
 
88
 
 
89
struct handshake_manager_equal : std::binary_function<const rak::socket_address*, const Handshake*, bool> {
 
90
  bool operator () (const rak::socket_address* sa1, const Handshake* p2) const {
 
91
    return p2->peer_info() != NULL && *sa1 == *rak::socket_address::cast_from(p2->peer_info()->socket_address());
 
92
  }
 
93
};
 
94
 
 
95
bool
 
96
HandshakeManager::find(const rak::socket_address& sa) {
 
97
  return std::find_if(base_type::begin(), base_type::end(), std::bind1st(handshake_manager_equal(), &sa)) != base_type::end();
 
98
}
 
99
 
 
100
void
 
101
HandshakeManager::erase_download(DownloadMain* info) {
 
102
  iterator split = std::partition(base_type::begin(), base_type::end(), rak::not_equal(info, std::mem_fun(&Handshake::download)));
 
103
 
 
104
  std::for_each(split, base_type::end(), std::ptr_fun(&handshake_manager_delete_handshake));
 
105
  base_type::erase(split, base_type::end());
 
106
}
 
107
 
 
108
void
 
109
HandshakeManager::add_incoming(SocketFd fd, const rak::socket_address& sa) {
 
110
  if (!manager->connection_manager()->can_connect() ||
 
111
      !manager->connection_manager()->filter(sa.c_sockaddr()) ||
 
112
      !setup_socket(fd)) {
 
113
    fd.close();
 
114
    return;
 
115
  }
 
116
 
 
117
  manager->connection_manager()->signal_handshake_log().emit(sa.c_sockaddr(), ConnectionManager::handshake_incoming, e_none, NULL);
 
118
  manager->connection_manager()->inc_socket_count();
 
119
 
 
120
  Handshake* h = new Handshake(fd, this, manager->connection_manager()->encryption_options());
 
121
  h->initialize_incoming(sa);
 
122
 
 
123
  base_type::push_back(h);
 
124
}
 
125
  
 
126
void
 
127
HandshakeManager::add_outgoing(const rak::socket_address& sa, DownloadMain* download) {
 
128
  if (!manager->connection_manager()->can_connect() ||
 
129
      !manager->connection_manager()->filter(sa.c_sockaddr()))
 
130
    return;
 
131
 
 
132
  create_outgoing(sa, download, manager->connection_manager()->encryption_options());
 
133
}
 
134
 
 
135
void
 
136
HandshakeManager::create_outgoing(const rak::socket_address& sa, DownloadMain* download, int encryptionOptions) {
 
137
  PeerInfo* peerInfo = download->peer_list()->connected(sa.c_sockaddr(),
 
138
                                                        PeerList::connect_keep_handshakes | PeerList::connect_filter_recent);
 
139
 
 
140
  if (peerInfo == NULL || peerInfo->failed_counter() > max_failed)
 
141
    return;
 
142
 
 
143
  SocketFd fd;
 
144
  const rak::socket_address* bindAddress = rak::socket_address::cast_from(manager->connection_manager()->bind_address());
 
145
  const rak::socket_address* connectAddress = &sa;
 
146
 
 
147
  if (rak::socket_address::cast_from(manager->connection_manager()->proxy_address())->is_valid()) {
 
148
    connectAddress = rak::socket_address::cast_from(manager->connection_manager()->proxy_address());
 
149
    encryptionOptions |= ConnectionManager::encryption_use_proxy;
 
150
  }
 
151
 
 
152
  if (!fd.open_stream() ||
 
153
      !setup_socket(fd) ||
 
154
      (bindAddress->is_bindable() && !fd.bind(*bindAddress)) ||
 
155
      !fd.connect(*connectAddress)) {
 
156
 
 
157
    if (fd.is_valid())
 
158
      fd.close();
 
159
 
 
160
    download->peer_list()->disconnected(peerInfo, 0);
 
161
    return;
 
162
  }
 
163
 
 
164
  int message;
 
165
 
 
166
  if (encryptionOptions & ConnectionManager::encryption_use_proxy)
 
167
    message = ConnectionManager::handshake_outgoing_proxy;
 
168
  else if (encryptionOptions & (ConnectionManager::encryption_try_outgoing | ConnectionManager::encryption_require))
 
169
    message = ConnectionManager::handshake_outgoing_encrypted;
 
170
  else
 
171
    message = ConnectionManager::handshake_outgoing;
 
172
 
 
173
  manager->connection_manager()->signal_handshake_log().emit(sa.c_sockaddr(), message, e_none, &download->info()->hash());
 
174
  manager->connection_manager()->inc_socket_count();
 
175
 
 
176
  Handshake* handshake = new Handshake(fd, this, encryptionOptions);
 
177
  handshake->initialize_outgoing(sa, download, peerInfo);
 
178
 
 
179
  base_type::push_back(handshake);
 
180
}
 
181
 
 
182
void
 
183
HandshakeManager::receive_succeeded(Handshake* handshake) {
 
184
  if (!handshake->is_active())
 
185
    throw internal_error("HandshakeManager::receive_succeeded(...) called on an inactive handshake.");
 
186
 
 
187
  erase(handshake);
 
188
  handshake->deactivate_connection();
 
189
 
 
190
  DownloadMain* download = handshake->download();
 
191
  PeerConnectionBase* pcb;
 
192
 
 
193
  if (download->info()->is_active() &&
 
194
 
 
195
      // We need to make libtorrent more selective in the clients it
 
196
      // connects to, and to move this somewhere else.
 
197
      (!download->file_list()->is_done() || !handshake->bitfield()->is_all_set() || download->initial_seeding() != NULL) &&
 
198
 
 
199
      (pcb = download->connection_list()->insert(handshake->peer_info(),
 
200
                                                 handshake->get_fd(),
 
201
                                                 handshake->bitfield(),
 
202
                                                 handshake->encryption()->info(),
 
203
                                                 handshake->extensions())) != NULL) {
 
204
    
 
205
    manager->client_list()->retrieve_id(&handshake->peer_info()->mutable_client_info(), handshake->peer_info()->id());
 
206
    manager->connection_manager()->signal_handshake_log().emit(handshake->peer_info()->socket_address(),
 
207
                                                               ConnectionManager::handshake_success,
 
208
                                                               e_none,
 
209
                                                               &download->info()->hash());
 
210
 
 
211
    pcb->peer_chunks()->set_have_timer(handshake->initialized_time());
 
212
 
 
213
    if (handshake->unread_size() != 0) {
 
214
      if (handshake->unread_size() > PeerConnectionBase::ProtocolRead::buffer_size)
 
215
        throw internal_error("HandshakeManager::receive_succeeded(...) Unread data won't fit PCB's read buffer.");
 
216
 
 
217
      pcb->push_unread(handshake->unread_data(), handshake->unread_size());
 
218
      pcb->event_read();
 
219
    }
 
220
 
 
221
    handshake->release_connection();
 
222
 
 
223
  } else {
 
224
    uint32_t reason;
 
225
 
 
226
    if (!download->info()->is_active())
 
227
      reason = e_handshake_inactive_download;
 
228
    else if (download->file_list()->is_done() && handshake->bitfield()->is_all_set())
 
229
      reason = e_handshake_unwanted_connection;
 
230
    else
 
231
      reason = e_handshake_duplicate;
 
232
 
 
233
    manager->connection_manager()->signal_handshake_log().emit(handshake->peer_info()->socket_address(),
 
234
                                                               ConnectionManager::handshake_dropped,
 
235
                                                               reason,
 
236
                                                               &download->info()->hash());
 
237
    handshake->destroy_connection();
 
238
  }
 
239
 
 
240
  delete handshake;
 
241
}
 
242
 
 
243
void
 
244
HandshakeManager::receive_failed(Handshake* handshake, int message, int error) {
 
245
  if (!handshake->is_active())
 
246
    throw internal_error("HandshakeManager::receive_failed(...) called on an inactive handshake.");
 
247
 
 
248
  const rak::socket_address* sa = handshake->socket_address();
 
249
 
 
250
  erase(handshake);
 
251
  handshake->deactivate_connection();
 
252
  handshake->destroy_connection();
 
253
 
 
254
  manager->connection_manager()->signal_handshake_log().emit(sa->c_sockaddr(),
 
255
                                                             message,
 
256
                                                             error,
 
257
                                                             handshake->download() != NULL ? &handshake->download()->info()->hash() : NULL);
 
258
  if (handshake->encryption()->should_retry()) {
 
259
    int retry_options = handshake->retry_options();
 
260
    DownloadMain* download = handshake->download();
 
261
 
 
262
    manager->connection_manager()->signal_handshake_log().emit(sa->c_sockaddr(),
 
263
                                                               retry_options & ConnectionManager::encryption_try_outgoing ?
 
264
                                                               ConnectionManager::handshake_retry_encrypted :
 
265
                                                               ConnectionManager::handshake_retry_plaintext,
 
266
                                                               e_none,
 
267
                                                               &download->info()->hash());
 
268
 
 
269
    create_outgoing(*sa, download, retry_options);
 
270
  }
 
271
 
 
272
  delete handshake;
 
273
}
 
274
 
 
275
void
 
276
HandshakeManager::receive_timeout(Handshake* h) {
 
277
  receive_failed(h, ConnectionManager::handshake_failed, h->state() == Handshake::CONNECTING ? e_handshake_network_unreachable : e_handshake_network_timeout);
 
278
}
 
279
 
 
280
bool
 
281
HandshakeManager::setup_socket(SocketFd fd) {
 
282
  if (!fd.set_nonblock())
 
283
    return false;
 
284
 
 
285
  ConnectionManager* m = manager->connection_manager();
 
286
 
 
287
  if (m->priority() != ConnectionManager::iptos_default && !fd.set_priority(m->priority()))
 
288
    return false;
 
289
 
 
290
  if (m->send_buffer_size() != 0 && !fd.set_send_buffer_size(m->send_buffer_size()))
 
291
    return false;
 
292
    
 
293
  if (m->receive_buffer_size() != 0 && !fd.set_receive_buffer_size(m->receive_buffer_size()))
 
294
    return false;
 
295
 
 
296
  return true;
 
297
}
 
298
 
 
299
}