📄 peer_connection_leech.cc
字号:
// beginning of the buffer. Or do we use position? Propably best, // therefor ProtocolBuffer::position() points to the beginning of // the unused data. try { // Normal read. // // We rarely will read zero bytes as the read of 64 bytes will // almost always either not fill up or it will require additional // reads. // // Only loop when end hits 64. do { switch (m_down->get_state()) { case ProtocolRead::IDLE: if (m_down->buffer()->size_end() == read_size) throw internal_error("PeerConnectionLeech::event_read() m_down->buffer()->size_end() == read_size."); m_down->buffer()->move_end(read_stream_throws(m_down->buffer()->end(), read_size - m_down->buffer()->size_end())); while (read_message()); if (m_down->buffer()->size_end() == read_size) { read_buffer_move_unused(); break; } else { read_buffer_move_unused(); return; } case ProtocolRead::READ_PIECE: if (!download_queue()->is_downloading()) throw internal_error("ProtocolRead::READ_PIECE state but RequestList is not downloading"); if (!m_downloadQueue.transfer()->is_valid() || !m_downloadQueue.transfer()->is_leader()) { m_down->set_state(ProtocolRead::READ_SKIP_PIECE); break; } if (!down_chunk()) return; m_tryRequest = true; m_down->set_state(ProtocolRead::IDLE); down_chunk_finished(); break; case ProtocolRead::READ_SKIP_PIECE: if (download_queue()->transfer()->is_leader()) { m_down->set_state(ProtocolRead::READ_PIECE); m_download->download_throttle()->insert(m_peerChunks.download_throttle()); break; } if (!down_chunk_skip()) return; m_tryRequest = true; m_down->set_state(ProtocolRead::IDLE); down_chunk_finished(); break; default: throw internal_error("PeerConnectionLeech::event_read() wrong state."); } // Figure out how to get rid of the shouldLoop boolean. } while (true); // Exception handlers: } catch (close_connection& e) { m_download->connection_list()->erase(this, 0); } catch (blocked_connection& e) { m_download->info()->signal_network_log().emit("Momentarily blocked read connection."); m_download->connection_list()->erase(this, 0); } catch (network_error& e) { m_download->info()->signal_network_log().emit(e.what()); m_download->connection_list()->erase(this, 0); } catch (storage_error& e) { m_download->info()->signal_storage_error().emit(e.what()); m_download->connection_list()->erase(this, 0); } catch (base_error& e) { std::stringstream s; s << "Connection read fd(" << get_fd().get_fd() << ',' << m_down->get_state() << ',' << m_down->last_command() << ") \"" << e.what() << '"'; e.set(s.str()); throw; }}inline voidPeerConnectionLeech::fill_write_buffer() { // No need to use delayed choke as we are a leecher. if (m_sendChoked && m_up->can_write_choke()) { m_sendChoked = false; m_up->write_choke(m_up->choked()); if (m_up->choked()) { m_download->upload_throttle()->erase(m_peerChunks.upload_throttle()); up_chunk_release(); m_peerChunks.upload_queue()->clear(); } else { m_download->upload_throttle()->insert(m_peerChunks.upload_throttle()); } } // Send the interested state before any requests as some clients, // e.g. BitTornado 0.7.14 and uTorrent 0.3.0, disconnect if a // request has been received while uninterested. The problem arises // as they send unchoke before receiving interested. if (m_sendInterested && m_up->can_write_interested()) { m_up->write_interested(m_up->interested()); m_sendInterested = false; } if (m_tryRequest && !(m_tryRequest = !should_request()) && !(m_tryRequest = try_request_pieces()) && !download_queue()->is_interested_in_active()) { m_sendInterested = true; m_up->set_interested(false); } while (!m_peerChunks.have_queue()->empty() && m_up->can_write_have()) { m_up->write_have(m_peerChunks.have_queue()->front()); m_peerChunks.have_queue()->pop_front(); } if (!m_up->choked() && !m_peerChunks.upload_queue()->empty() && m_up->can_write_piece()) write_prepare_piece();}voidPeerConnectionLeech::event_write() { try { do { switch (m_up->get_state()) { case ProtocolWrite::IDLE: // We might have buffered keepalive message or similar, but // 'end' should remain at the start of the buffer. if (m_up->buffer()->size_end() != 0) throw internal_error("PeerConnectionLeech::event_write() ProtocolWrite::IDLE in a wrong state."); // Fill up buffer. fill_write_buffer(); if (m_up->buffer()->size_position() == 0) { manager->poll()->remove_write(this); return; } m_up->set_state(ProtocolWrite::MSG); m_up->buffer()->prepare_end(); case ProtocolWrite::MSG: m_up->buffer()->move_position(write_stream_throws(m_up->buffer()->position(), m_up->buffer()->remaining())); if (m_up->buffer()->remaining()) return; m_up->buffer()->reset(); if (m_up->last_command() != ProtocolBase::PIECE) { // Break or loop? Might do an ifelse based on size of the // write buffer. Also the write buffer is relatively large. m_up->set_state(ProtocolWrite::IDLE); break; } // We're uploading a piece. load_up_chunk(); m_up->set_state(ProtocolWrite::WRITE_PIECE); case ProtocolWrite::WRITE_PIECE: if (!up_chunk()) return; m_up->set_state(ProtocolWrite::IDLE); break; default: throw internal_error("PeerConnectionLeech::event_write() wrong state."); } } while (true); } catch (close_connection& e) { m_download->connection_list()->erase(this, 0); } catch (blocked_connection& e) { m_download->info()->signal_network_log().emit("Momentarily blocked write connection."); m_download->connection_list()->erase(this, 0); } catch (network_error& e) { m_download->info()->signal_network_log().emit(e.what()); m_download->connection_list()->erase(this, 0); } catch (storage_error& e) { m_download->info()->signal_storage_error().emit(e.what()); m_download->connection_list()->erase(this, 0); } catch (base_error& e) { std::stringstream s; s << "Connection write fd(" << get_fd().get_fd() << ',' << m_up->get_state() << ',' << m_up->last_command() << ") \"" << e.what() << '"'; e.set(s.str()); throw; }}voidPeerConnectionLeech::read_have_chunk(uint32_t index) { if (index >= m_peerChunks.bitfield()->size_bits()) throw network_error("Peer sent HAVE message with out-of-range index."); if (m_peerChunks.bitfield()->get(index)) return; m_download->chunk_statistics()->received_have_chunk(&m_peerChunks, index, m_download->content()->chunk_size()); if (m_peerChunks.bitfield()->is_all_set()) if (m_download->content()->is_done()) throw close_connection(); else set_remote_not_interested(); if (m_download->content()->is_done()) return; if (is_up_interested()) { if (!m_tryRequest && m_download->chunk_selector()->received_have_chunk(&m_peerChunks, index)) { m_tryRequest = true; write_insert_poll_safe(); } } else { if (m_download->chunk_selector()->received_have_chunk(&m_peerChunks, index)) { m_sendInterested = true; m_up->set_interested(true); // Is it enough to insert into write here? Make the interested // check branch to include insert_write, even when not sending // interested. m_tryRequest = true; write_insert_poll_safe(); } }}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -