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