1 /* <!-- copyright */
2 /*
3 * aria2 - The high speed download utility
4 *
5 * Copyright (C) 2006 Tatsuhiro Tsujikawa
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 * In addition, as a special exception, the copyright holders give
22 * permission to link the code of portions of this program with the
23 * OpenSSL library under certain conditions as described in each
24 * individual source file, and distribute linked combinations
25 * including the two.
26 * You must obey the GNU General Public License in all respects
27 * for all of the code used other than OpenSSL. If you modify
28 * file(s) with this exception, you may extend this exception to your
29 * version of the file(s), but you are not obligated to do so. If you
30 * do not wish to do so, delete this exception statement from your
31 * version. If you delete this exception statement from all source
32 * files in the program, then also delete it here.
33 */
34 /* copyright --> */
35 #include "ReceiverMSEHandshakeCommand.h"
36 #include "PeerReceiveHandshakeCommand.h"
37 #include "PeerConnection.h"
38 #include "DownloadEngine.h"
39 #include "BtHandshakeMessage.h"
40 #include "DlAbortEx.h"
41 #include "Peer.h"
42 #include "message.h"
43 #include "SocketCore.h"
44 #include "Logger.h"
45 #include "prefs.h"
46 #include "Option.h"
47 #include "MSEHandshake.h"
48 #include "ARC4Encryptor.h"
49 #include "RequestGroupMan.h"
50 #include "BtRegistry.h"
51 #include "DownloadContext.h"
52 #include "array_fun.h"
53
54 namespace aria2 {
55
ReceiverMSEHandshakeCommand(cuid_t cuid,const std::shared_ptr<Peer> & peer,DownloadEngine * e,const std::shared_ptr<SocketCore> & s)56 ReceiverMSEHandshakeCommand::ReceiverMSEHandshakeCommand(
57 cuid_t cuid, const std::shared_ptr<Peer>& peer, DownloadEngine* e,
58 const std::shared_ptr<SocketCore>& s)
59 :
60
61 PeerAbstractCommand(cuid, peer, e, s),
62 sequence_(RECEIVER_IDENTIFY_HANDSHAKE),
63 mseHandshake_(make_unique<MSEHandshake>(cuid, s, e->getOption()))
64 {
65 setTimeout(std::chrono::seconds(
66 e->getOption()->getAsInt(PREF_PEER_CONNECTION_TIMEOUT)));
67 mseHandshake_->setWantRead(true);
68 }
69
70 ReceiverMSEHandshakeCommand::~ReceiverMSEHandshakeCommand() = default;
71
exitBeforeExecute()72 bool ReceiverMSEHandshakeCommand::exitBeforeExecute()
73 {
74 return getDownloadEngine()->isHaltRequested() ||
75 getDownloadEngine()->getRequestGroupMan()->downloadFinished();
76 }
77
executeInternal()78 bool ReceiverMSEHandshakeCommand::executeInternal()
79 {
80 if (mseHandshake_->getWantRead()) {
81 mseHandshake_->read();
82 }
83 bool done = false;
84 while (!done) {
85 switch (sequence_) {
86 case RECEIVER_IDENTIFY_HANDSHAKE: {
87 MSEHandshake::HANDSHAKE_TYPE type =
88 mseHandshake_->identifyHandshakeType();
89 switch (type) {
90 case MSEHandshake::HANDSHAKE_NOT_YET:
91 done = true;
92 break;
93 case MSEHandshake::HANDSHAKE_ENCRYPTED:
94 mseHandshake_->initEncryptionFacility(false);
95 sequence_ = RECEIVER_WAIT_KEY;
96 break;
97 case MSEHandshake::HANDSHAKE_LEGACY: {
98 const auto option = getDownloadEngine()->getOption();
99 if (option->getAsBool(PREF_BT_FORCE_ENCRYPTION) ||
100 option->getAsBool(PREF_BT_REQUIRE_CRYPTO)) {
101 throw DL_ABORT_EX(
102 "The legacy BitTorrent handshake is not acceptable by the"
103 " preference.");
104 }
105 auto peerConnection =
106 make_unique<PeerConnection>(getCuid(), getPeer(), getSocket());
107 peerConnection->presetBuffer(mseHandshake_->getBuffer(),
108 mseHandshake_->getBufferLength());
109 getDownloadEngine()->addCommand(
110 make_unique<PeerReceiveHandshakeCommand>(
111 getCuid(), getPeer(), getDownloadEngine(), getSocket(),
112 std::move(peerConnection)));
113 return true;
114 }
115 default:
116 throw DL_ABORT_EX("Not supported handshake type.");
117 }
118 break;
119 }
120 case RECEIVER_WAIT_KEY: {
121 if (mseHandshake_->receivePublicKey()) {
122 mseHandshake_->sendPublicKey();
123 sequence_ = RECEIVER_SEND_KEY_PENDING;
124 }
125 else {
126 done = true;
127 }
128 break;
129 }
130 case RECEIVER_SEND_KEY_PENDING:
131 if (mseHandshake_->send()) {
132 sequence_ = RECEIVER_FIND_HASH_MARKER;
133 }
134 else {
135 done = true;
136 }
137 break;
138 case RECEIVER_FIND_HASH_MARKER: {
139 if (mseHandshake_->findReceiverHashMarker()) {
140 sequence_ = RECEIVER_RECEIVE_PAD_C_LENGTH;
141 }
142 else {
143 done = true;
144 }
145 break;
146 }
147 case RECEIVER_RECEIVE_PAD_C_LENGTH: {
148 std::vector<std::shared_ptr<DownloadContext>> downloadContexts;
149 getDownloadEngine()->getBtRegistry()->getAllDownloadContext(
150 std::back_inserter(downloadContexts));
151 if (mseHandshake_->receiveReceiverHashAndPadCLength(downloadContexts)) {
152 sequence_ = RECEIVER_RECEIVE_PAD_C;
153 }
154 else {
155 done = true;
156 }
157 break;
158 }
159 case RECEIVER_RECEIVE_PAD_C: {
160 if (mseHandshake_->receivePad()) {
161 sequence_ = RECEIVER_RECEIVE_IA_LENGTH;
162 }
163 else {
164 done = true;
165 }
166 break;
167 }
168 case RECEIVER_RECEIVE_IA_LENGTH: {
169 if (mseHandshake_->receiveReceiverIALength()) {
170 sequence_ = RECEIVER_RECEIVE_IA;
171 }
172 else {
173 done = true;
174 }
175 break;
176 }
177 case RECEIVER_RECEIVE_IA: {
178 if (mseHandshake_->receiveReceiverIA()) {
179 mseHandshake_->sendReceiverStep2();
180 sequence_ = RECEIVER_SEND_STEP2_PENDING;
181 }
182 else {
183 done = true;
184 }
185 break;
186 }
187 case RECEIVER_SEND_STEP2_PENDING:
188 if (mseHandshake_->send()) {
189 createCommand();
190 return true;
191 }
192 else {
193 done = true;
194 }
195 break;
196 }
197 }
198 if (mseHandshake_->getWantRead()) {
199 setReadCheckSocket(getSocket());
200 }
201 else {
202 disableReadCheckSocket();
203 }
204 if (mseHandshake_->getWantWrite()) {
205 setWriteCheckSocket(getSocket());
206 }
207 else {
208 disableWriteCheckSocket();
209 }
210 addCommandSelf();
211 return false;
212 }
213
createCommand()214 void ReceiverMSEHandshakeCommand::createCommand()
215 {
216 auto peerConnection =
217 make_unique<PeerConnection>(getCuid(), getPeer(), getSocket());
218 if (mseHandshake_->getNegotiatedCryptoType() == MSEHandshake::CRYPTO_ARC4) {
219 peerConnection->enableEncryption(mseHandshake_->popEncryptor(),
220 mseHandshake_->popDecryptor());
221 }
222 // Since initiator cannot send payload stream before reading step2
223 // from receiver, mseHandshake_->getBufferLength() should be 0.
224 peerConnection->presetBuffer(mseHandshake_->getIA(),
225 mseHandshake_->getIALength());
226 // TODO add mseHandshake_->getInfoHash() to PeerReceiveHandshakeCommand
227 // as a hint. If this info hash and one in BitTorrent Handshake does not
228 // match, then drop connection.
229 getDownloadEngine()->addCommand(make_unique<PeerReceiveHandshakeCommand>(
230 getCuid(), getPeer(), getDownloadEngine(), getSocket(),
231 std::move(peerConnection)));
232 }
233
234 } // namespace aria2
235