📄 peerlist.cpp
字号:
if( INVALID_SOCKET != m_listen_sock && m_peers_count < cfg_max_peers){ FD_SET(m_listen_sock, rfdp); if( maxfd < m_listen_sock ) maxfd = m_listen_sock; } if( f_unchoke_check && UNCHOKER ){ m_unchoke_check_timestamp = now; // time of the last unchoke check if (!m_opt_timestamp) m_opt_timestamp = now; if( !UNCHOKER[0] ) Self.StopULTimer(); for( int i = 0; i < m_max_unchoke + 1; i++ ){ if( !UNCHOKER[i] ) break; if( PEER_IS_FAILED(UNCHOKER[i]) ) continue; sk = UNCHOKER[i]->stream.GetSocket(); if( UNCHOKER[i]->SetLocal(M_UNCHOKE) < 0 ){ if(arg_verbose) CONSOLE.Debug("close: Can't unchoke peer"); UNCHOKER[i]->CloseConnection(); FD_CLR(sk,rfdp); FD_CLR(sk,wfdp); continue; } if( !FD_ISSET(sk,wfdp) && UNCHOKER[i]->NeedWrite((int)m_f_limitu) ){ FD_SET(sk,wfdp); if( maxfd < sk) maxfd = sk; } } // end for delete []UNCHOKER; } return maxfd;}void PeerList::SetUnchokeIntervals(){ time_t old_unchoke_int = m_unchoke_interval, old_opt_int = m_opt_interval; // Unchoke peers long enough to have a chance at getting some data. if( BandWidthLimitUp() && BTCONTENT.Seeding() ){ int optx = (int)( 1 / (1 - (double)MIN_UNCHOKE_INTERVAL * cfg_max_bandwidth_up / cfg_req_slice_size) ); if( optx < 0 ) optx = 0; if( optx < MIN_OPT_CYCLE ){ optx = MIN_OPT_CYCLE; double interval = cfg_req_slice_size / (cfg_max_bandwidth_up * MIN_OPT_CYCLE / (double)(MIN_OPT_CYCLE-1)); m_unchoke_interval = (size_t)interval; if( interval - (int)interval > 0 ) m_unchoke_interval++; if( m_unchoke_interval < MIN_UNCHOKE_INTERVAL ) m_unchoke_interval = MIN_UNCHOKE_INTERVAL; }else{ // Allow each peer at least 60 seconds unchoked. m_unchoke_interval = MIN_UNCHOKE_INTERVAL; if( m_max_unchoke+1 < 60 / m_unchoke_interval ){ int maxopt = (int)( 1 / (1 - (double)(m_max_unchoke+1) * m_unchoke_interval / 60) ); if( maxopt > MIN_OPT_CYCLE && optx > maxopt ) optx = maxopt; } if( optx > m_max_unchoke+2 ) optx = m_max_unchoke+2; } m_opt_interval = optx * m_unchoke_interval; }else if( BandWidthLimitUp() && !BTCONTENT.Seeding() ){ // Need to be able to upload a slice per interval. double interval = cfg_req_slice_size / (double)cfg_max_bandwidth_up; m_unchoke_interval = (size_t)interval; if( interval - (int)interval > 0 ) m_unchoke_interval++; if( m_unchoke_interval < MIN_UNCHOKE_INTERVAL ) m_unchoke_interval = MIN_UNCHOKE_INTERVAL; m_opt_interval = MIN_OPT_CYCLE * m_unchoke_interval; }else{ m_unchoke_interval = MIN_UNCHOKE_INTERVAL; m_opt_interval = MIN_OPT_CYCLE * MIN_UNCHOKE_INTERVAL; } m_prev_limit_up = cfg_max_bandwidth_up; m_interval_timestamp = now; if( arg_verbose && (m_unchoke_interval != old_unchoke_int || m_opt_interval != old_opt_int) ) CONSOLE.Debug("ulimit %d, unchoke interval %d, opt interval %d", (int)cfg_max_bandwidth_up, (int)m_unchoke_interval, (int)m_opt_interval);}btPeer* PeerList::Who_Can_Abandon(btPeer *proposer){ PEERNODE *p; btPeer *peer = (btPeer*) 0; PSLICE ps; size_t idx; for( p = m_head; p; p = p->next ){ if(!PEER_IS_SUCCESS(p->peer) || p->peer == proposer || p->peer->request_q.IsEmpty() ) continue; if( (peer && p->peer->NominalDL() < peer->NominalDL()) || (!peer && p->peer->NominalDL() * 1.5 < proposer->NominalDL()) ){ idx = p->peer->request_q.GetRequestIdx(); if( proposer->bitfield.IsSet(idx) && !proposer->request_q.HasIdx(idx) ) peer = p->peer; else{ ps = p->peer->request_q.GetHead(); for( ; ps; ps = ps->next ){ if( idx == ps->index ) continue; idx = ps->index; if( proposer->bitfield.IsSet(idx) && !proposer->request_q.HasIdx(idx) ){ peer = p->peer; break; } } } } } //end for if( peer && arg_verbose ) CONSOLE.Debug("Abandoning %p (%d B/s) for %p (%d B/s)", peer, peer->NominalDL(), proposer, proposer->NominalDL()); return peer;}// This takes an index parameter to facilitate modification of the function to// allow targeting of a specific piece. It's currently only used as a flag to// specify endgame or initial-piece mode though.size_t PeerList::What_Can_Duplicate(BitField &bf, const btPeer *proposer, size_t idx){ struct qdata { size_t idx, qlen, count; }; struct qdata *data; int endgame, pass, i, mark; PEERNODE *p; PSLICE ps; size_t slots, piece, qsize; double work, best; endgame = idx < BTCONTENT.GetNPieces(); // else initial-piece mode slots = endgame ? BTCONTENT.GetNPieces() - BTCONTENT.pBF->Count() : m_downloads * 2; if( slots < m_dup_req_pieces + 2 ) slots = m_dup_req_pieces + 2; data = new struct qdata[slots];#ifndef WINDOWS if( !data ) return BTCONTENT.GetNPieces();#endif // In initial mode, only dup a piece with trade value. // In endgame mode, dup any if there are no pieces with trade value. FindValuedPieces(bf, proposer, !endgame); if( bf.IsEmpty() ){ if(endgame) bf = proposer->bitfield; else return BTCONTENT.GetNPieces(); } // initialize data[0].idx = BTCONTENT.GetNPieces(); data[0].qlen = 0; data[0].count = 0; for( i = 1; i < slots; i++ ) memcpy(data + i, data, sizeof(struct qdata)); // measure applicable piece request queues for( p = m_head; p; p = p->next ){ if( !PEER_IS_SUCCESS(p->peer) || p->peer == proposer || p->peer->request_q.IsEmpty() ) continue; piece = BTCONTENT.GetNPieces(); ps = p->peer->request_q.GetHead(); for( ; ps; ps = ps->next ){ if( piece == ps->index || !bf.IsSet(ps->index) || proposer->request_q.HasIdx(ps->index) ) continue; piece = ps->index; qsize = p->peer->request_q.Qlen(piece); // insert queue data into array at (idx % slots) pass = 0; i = piece % slots; while( data[i].idx < BTCONTENT.GetNPieces() && pass < 2 ){ if( piece == data[i].idx ) break; i++; if( i >= slots ){ i = 0; pass++; } } if( pass < 2 ){ if( data[i].idx == BTCONTENT.GetNPieces() ){ data[i].idx = piece; data[i].qlen = qsize; } data[i].count++; } } } // end of measurement loop /* Find the best workload for initial/endgame. In endgame mode, request the piece that should take the longest. In initial mode, request the piece that should complete the fastest. */ best = endgame ? 0 : BTCONTENT.GetPieceLength() / cfg_req_slice_size + 2; mark = slots; for( i = 0; i < slots; i++ ){ if( data[i].idx == BTCONTENT.GetNPieces() ) continue; work = data[i].qlen / (double)(data[i].count); if( work > 1 && (endgame ? work > best : work < best) ){ best = work; mark = i; } } if( mark < slots && data[mark].count == 1 ) m_dup_req_pieces++; CONSOLE.Debug("%d dup req pieces", (int)m_dup_req_pieces); delete []data; return (mark < slots) ? data[mark].idx : BTCONTENT.GetNPieces();}void PeerList::FindValuedPieces(BitField &bf, const btPeer *proposer, int initial) const{ PEERNODE *p; BitField bf_all_have = bf, bf_int_have = bf, bf_others_have, bf_only_he_has = bf, *pbf_prefer; for( p = m_head; p; p = p->next ){ if( !PEER_IS_SUCCESS(p->peer) || p->peer == proposer ) continue; if( p->peer->Need_Remote_Data() ) bf_int_have.And(p->peer->bitfield); bf_all_have.And(p->peer->bitfield); if( !initial && !p->peer->bitfield.IsFull() ) bf_only_he_has.Except(p->peer->bitfield); else bf_others_have.Comb(p->peer->bitfield); } /* bf_all_have is now pertinent pieces that all peers have bf_int_have is pertinent pieces that all peers in which I'm interested have We prefer to get pieces that those peers need, if we can. Otherwise go for pieces that any peer needs in hopes of future reciprocation. */ if( !bf_int_have.IsFull() ) bf_all_have = bf_int_have; bf_all_have.Invert(); bf.And(bf_all_have); // bf is now pertinent pieces that not everyone has pbf_prefer = initial ? &bf_others_have : &bf_only_he_has; BitField tmpBitField = bf; tmpBitField.And(*pbf_prefer); /* If initial mode, tmpBitField is now pertinent pieces that more than one peer has, but not everyone. Otherwise, it's pertinent pieces that only the proposer has (not considering what other seeders have). In either case if there are no such pieces, revert to the simple answer.*/ if( !tmpBitField.IsEmpty() ) bf = tmpBitField;}/* Find a peer with the given piece in its request queue. Duplicating a request queue that's in progress rather than creating a new one helps avoid requesting slices that we already have. */btPeer *PeerList::WhoHas(size_t idx) const{ PEERNODE *p; btPeer *peer = (btPeer*) 0; for( p = m_head; p; p = p->next ){ if( p->peer->request_q.HasIdx(idx) ){ peer = p->peer; break; } } return peer;}int PeerList::HasSlice(size_t idx, size_t off, size_t len) const{ PEERNODE *p; for( p = m_head; p; p = p->next ){ if( p->peer->request_q.HasSlice(idx, off, len) ) break; } return p ? 1 : 0;}/* If another peer has the same slice requested first, move the proposer's slice to the last position for the piece. */void PeerList::CompareRequest(btPeer *proposer, size_t idx){ PSLICE ps, qs; PEERNODE *p; size_t qlen, count=0; ps = proposer->request_q.GetHead(); for( ; ps && idx != ps->index; ps = ps->next ); if( !ps ) return; qlen = proposer->request_q.Qlen(idx); do{ for( p = m_head; p; p = p->next ){ if( !PEER_IS_SUCCESS(p->peer) || p->peer->request_q.IsEmpty() ) continue; qs = p->peer->request_q.GetHead(); for( ; qs && idx != qs->index; qs = qs->next ); if( qs && ps->index == qs->index && ps->offset == qs->offset && ps->length == qs->length ){ qs = ps->next; proposer->request_q.MoveLast(ps); ps = qs; break; } } }while( p && ++count < qlen );}int PeerList::CancelSlice(size_t idx, size_t off, size_t len){ PEERNODE *p; int t, r=0; for( p = m_head; p; p = p->next ){ if( !PEER_IS_SUCCESS(p->peer) ) continue; t = p->peer->CancelSliceRequest(idx, off, len); if( t ){ r = 1; if( t < 0 ){ if(arg_verbose) CONSOLE.Debug("close: CancelSlice"); p->peer->CloseConnection(); } } } return r;}int PeerList::CancelPiece(size_t idx){ PEERNODE *p; int t, r=0; for( p = m_head; p; p = p->next ){ if( !PEER_IS_SUCCESS(p->peer) ) continue; t = p->peer->CancelPiece(idx); if( t ){ r = 1; if( t < 0 ){ if(arg_verbose) CONSOLE.Debug("close: CancelPiece"); p->peer->CloseConnection(); } } } return r;}// Cancel one peer's request for a specific piece.void PeerList::CancelOneRequest(size_t idx){ PEERNODE *p; PSLICE ps; btPeer *peer = (btPeer *)0; int count, max=0, dupcount=0, pending = 0; if( PENDINGQUEUE.Exist(idx) ){ pending = 1; dupcount++; } for( p = m_head; p; p = p->next ){ if( !PEER_IS_SUCCESS(p->peer) ) continue; // select the peer with the most requests ahead of the target piece count = 0; ps = p->peer->request_q.GetHead(); for( ; ps; ps = ps->next ){ if( ps->index == idx ) break; else count++; } if( ps ){ dupcount++; // in a tie, select the slower peer if( count > max || !peer || (!pending && count == max && p->peer->NominalDL() < peer->NominalDL()) ){ peer = p->peer; max = count; } } } if( peer && dupcount > peer->request_q.Qlen(idx) ){ if( pending ) PENDINGQUEUE.Delete(idx); else{ CONSOLE.Debug("Cancel #%d on %p (%d B/s)", (int)idx, peer, (int)(peer->NominalDL())); peer->CancelPiece(idx); } if( dupcount == 2 ){ // was 2, now only 1 m_dup_req_pieces--; CONSOLE.Debug("%d dup req pieces", (int)m_dup_req_pieces); } }}void PeerList::RecalcDupReqs(){ PEERNODE *p; PSLICE ps;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -