/* */ #include "ReceiverMSEHandshakeCommand.h" #include "PeerReceiveHandshakeCommand.h" #include "PeerConnection.h" #include "DownloadEngine.h" #include "BtHandshakeMessage.h" #include "DlAbortEx.h" #include "Peer.h" #include "message.h" #include "SocketCore.h" #include "Logger.h" #include "prefs.h" #include "Option.h" #include "MSEHandshake.h" #include "ARC4Encryptor.h" #include "RequestGroupMan.h" #include "BtRegistry.h" #include "DownloadContext.h" #include "array_fun.h" namespace aria2 { ReceiverMSEHandshakeCommand::ReceiverMSEHandshakeCommand (cuid_t cuid, const std::shared_ptr& peer, DownloadEngine* e, const std::shared_ptr& s): PeerAbstractCommand(cuid, peer, e, s), sequence_(RECEIVER_IDENTIFY_HANDSHAKE), mseHandshake_(make_unique(cuid, s, e->getOption())) { setTimeout(e->getOption()->getAsInt(PREF_PEER_CONNECTION_TIMEOUT)); mseHandshake_->setWantRead(true); } ReceiverMSEHandshakeCommand::~ReceiverMSEHandshakeCommand() {} bool ReceiverMSEHandshakeCommand::exitBeforeExecute() { return getDownloadEngine()->isHaltRequested() || getDownloadEngine()->getRequestGroupMan()->downloadFinished(); } bool ReceiverMSEHandshakeCommand::executeInternal() { if(mseHandshake_->getWantRead()) { mseHandshake_->read(); } bool done = false; while(!done) { switch(sequence_) { case RECEIVER_IDENTIFY_HANDSHAKE: { MSEHandshake::HANDSHAKE_TYPE type = mseHandshake_->identifyHandshakeType(); switch(type) { case MSEHandshake::HANDSHAKE_NOT_YET: done = true; break; case MSEHandshake::HANDSHAKE_ENCRYPTED: mseHandshake_->initEncryptionFacility(false); sequence_ = RECEIVER_WAIT_KEY; break; case MSEHandshake::HANDSHAKE_LEGACY: { const auto option = getDownloadEngine()->getOption(); if(option->getAsBool(PREF_BT_FORCE_ENCRYPTION) || option->getAsBool(PREF_BT_REQUIRE_CRYPTO)){ throw DL_ABORT_EX ("The legacy BitTorrent handshake is not acceptable by the" " preference."); } auto peerConnection = make_unique (getCuid(), getPeer(), getSocket()); peerConnection->presetBuffer(mseHandshake_->getBuffer(), mseHandshake_->getBufferLength()); getDownloadEngine()->addCommand (make_unique (getCuid(), getPeer(), getDownloadEngine(), getSocket(), std::move(peerConnection))); return true; } default: throw DL_ABORT_EX("Not supported handshake type."); } break; } case RECEIVER_WAIT_KEY: { if(mseHandshake_->receivePublicKey()) { mseHandshake_->sendPublicKey(); sequence_ = RECEIVER_SEND_KEY_PENDING; } else { done = true; } break; } case RECEIVER_SEND_KEY_PENDING: if(mseHandshake_->send()) { sequence_ = RECEIVER_FIND_HASH_MARKER; } else { done = true; } break; case RECEIVER_FIND_HASH_MARKER: { if(mseHandshake_->findReceiverHashMarker()) { sequence_ = RECEIVER_RECEIVE_PAD_C_LENGTH; } else { done = true; } break; } case RECEIVER_RECEIVE_PAD_C_LENGTH: { std::vector > downloadContexts; getDownloadEngine()->getBtRegistry()->getAllDownloadContext (std::back_inserter(downloadContexts)); if(mseHandshake_->receiveReceiverHashAndPadCLength(downloadContexts)) { sequence_ = RECEIVER_RECEIVE_PAD_C; } else { done = true; } break; } case RECEIVER_RECEIVE_PAD_C: { if(mseHandshake_->receivePad()) { sequence_ = RECEIVER_RECEIVE_IA_LENGTH; } else { done = true; } break; } case RECEIVER_RECEIVE_IA_LENGTH: { if(mseHandshake_->receiveReceiverIALength()) { sequence_ = RECEIVER_RECEIVE_IA; } else { done = true; } break; } case RECEIVER_RECEIVE_IA: { if(mseHandshake_->receiveReceiverIA()) { mseHandshake_->sendReceiverStep2(); sequence_ = RECEIVER_SEND_STEP2_PENDING; } else { done = true; } break; } case RECEIVER_SEND_STEP2_PENDING: if(mseHandshake_->send()) { createCommand(); return true; } else { done = true; } break; } } if(mseHandshake_->getWantRead()) { setReadCheckSocket(getSocket()); } else { disableReadCheckSocket(); } if(mseHandshake_->getWantWrite()) { setWriteCheckSocket(getSocket()); } else { disableWriteCheckSocket(); } addCommandSelf(); return false; } void ReceiverMSEHandshakeCommand::createCommand() { auto peerConnection = make_unique (getCuid(), getPeer(), getSocket()); if(mseHandshake_->getNegotiatedCryptoType() == MSEHandshake::CRYPTO_ARC4) { peerConnection->enableEncryption(mseHandshake_->popEncryptor(), mseHandshake_->popDecryptor()); } // Since initiator cannot send payload stream before reading step2 // from receiver, mseHandshake_->getBufferLength() should be 0. peerConnection->presetBuffer(mseHandshake_->getIA(), mseHandshake_->getIALength()); // TODO add mseHandshake_->getInfoHash() to PeerReceiveHandshakeCommand // as a hint. If this info hash and one in BitTorrent Handshake does not // match, then drop connection. getDownloadEngine()->addCommand(make_unique (getCuid(), getPeer(), getDownloadEngine(), getSocket(), std::move(peerConnection))); } } // namespace aria2