📄 peerlist.cpp
字号:
} if( !Self.OntimeDL() && !Self.OntimeUL() ){ FD_CLR(sk,rfdnextp); peer->CloseConnection(); } }else if( FD_ISSET(sk,wfdp) ){ (*nready)--; if( !Self.OntimeDL() && !Self.OntimeUL() ){ FD_CLR(sk,wfdnextp); if( peer->Send_ShakeInfo() < 0 ){ if(arg_verbose) CONSOLE.Debug("close: Sending handshake"); peer->CloseConnection(); }else peer->SetStatus(P_HANDSHAKE); } } } }// end for if( !m_ul_limited && !BandWidthLimitUp() ) m_missed_count++;}void PeerList::CloseAllConnectionToSeed(){ PEERNODE *p = m_head; for( ; p; p = p->next ){ if( p->peer->bitfield.IsFull() || /* Drop peers who remain uninterested, but keep recent connections. Peers who connected recently will resolve by bitfield exchange. */ (PEER_IS_SUCCESS(p->peer) && !p->peer->Is_Remote_Interested() && BTCONTENT.GetSeedTime() - now >= 300 && !p->peer->ConnectedWhileSeed()) ){ p->peer->DontWantAgain(); if(arg_verbose) CONSOLE.Debug("close: seed<->seed"); p->peer->CloseConnection(); } else p->peer->stream.in_buffer.SetSize(BUF_DEF_SIZ); }}int PeerList::UnChokeCheck(btPeer* peer, btPeer *peer_array[]){ int i = 0; int cancel_idx = 0; btPeer *loster = (btPeer*) 0; int f_seed = BTCONTENT.Seeding(); int no_opt = 0; unsigned long rndbits; int r=0; int retval = 0; if(m_opt_timestamp) no_opt = 1; if(f_seed) no_opt = 1 - no_opt;// Find my 3 or 4 fastest peers.// The m_max_unchoke+1 (4th) slot is for the optimistic unchoke when it happens. // Find a slot for the candidate--the slowest peer, or an available slot. for( cancel_idx = i = 0; i < m_max_unchoke + no_opt; i++ ){ if((btPeer*) 0 == peer_array[i] || PEER_IS_FAILED(peer_array[i]) ){ // 有空位 cancel_idx = i; break; }else{ if(cancel_idx == i) continue; if(f_seed){ // compare time unchoked if( (!peer_array[i]->Is_Local_UnChoked() && (peer_array[cancel_idx]->Is_Local_UnChoked() || peer_array[cancel_idx]->GetLastUnchokeTime() < peer_array[i]->GetLastUnchokeTime())) || (peer_array[i]->Is_Local_UnChoked() && peer_array[cancel_idx]->Is_Local_UnChoked() && peer_array[i]->GetLastUnchokeTime() < peer_array[cancel_idx]->GetLastUnchokeTime()) ) cancel_idx = i; }else{ // compare download rate. if( peer_array[cancel_idx]->RateDL() > peer_array[i]->RateDL() //if equal, reciprocate to the peer we've sent less to, proportionally ||(peer_array[cancel_idx]->RateDL() == peer_array[i]->RateDL() && peer_array[cancel_idx]->TotalUL() / (peer_array[cancel_idx]->TotalDL()+.001) < peer_array[i]->TotalUL() / (peer_array[i]->TotalDL()+.001)) ) cancel_idx = i; } } } // end for if( (btPeer*) 0 != peer_array[cancel_idx] && PEER_IS_SUCCESS(peer_array[cancel_idx]) ){ if(f_seed){ if( (!peer_array[cancel_idx]->Is_Local_UnChoked() && (peer->Is_Local_UnChoked() || peer->GetLastUnchokeTime() < peer_array[cancel_idx]->GetLastUnchokeTime())) || (peer_array[cancel_idx]->Is_Local_UnChoked() && peer->Is_Local_UnChoked() && peer_array[cancel_idx]->GetLastUnchokeTime() < peer->GetLastUnchokeTime()) ){ loster = peer_array[cancel_idx]; peer_array[cancel_idx] = peer; }else loster = peer; }else{ if( peer->RateDL() > peer_array[cancel_idx]->RateDL() // If equal, reciprocate to the peer we've sent less to, proportionally ||(peer_array[cancel_idx]->RateDL() == peer->RateDL() && peer_array[cancel_idx]->TotalUL() / (peer_array[cancel_idx]->TotalDL()+.001) > peer->TotalUL() / (peer->TotalDL()+.001)) ){ loster = peer_array[cancel_idx]; peer_array[cancel_idx] = peer; }else loster = peer; } // opt unchoke if( no_opt ){ if( loster->SetLocal(M_CHOKE) < 0 ){ loster->CloseConnection(); if( peer==loster ) retval = -1; } } else // The last slot is for the optimistic unchoke. if( (btPeer*) 0 == peer_array[m_max_unchoke] || PEER_IS_FAILED(peer_array[m_max_unchoke]) ) peer_array[m_max_unchoke] = loster; else { if( !r-- ){ rndbits = random(); r = 15; } // if loser is empty and current is not, loser gets 75% chance. if( loster->IsEmpty() && !peer_array[m_max_unchoke]->IsEmpty() && (rndbits>>=2)&3 ){ btPeer* tmp = peer_array[m_max_unchoke]; peer_array[m_max_unchoke] = loster; loster = tmp; } else // This mess chooses the loser: // if loser is choked and current is not // OR if both are choked and loser has waited longer // OR if both are unchoked and loser has had less time unchoked. if( (!loster->Is_Local_UnChoked() && ( peer_array[m_max_unchoke]->Is_Local_UnChoked() || loster->GetLastUnchokeTime() < peer_array[m_max_unchoke]->GetLastUnchokeTime() )) || (loster->Is_Local_UnChoked() && peer_array[m_max_unchoke]->Is_Local_UnChoked() && peer_array[m_max_unchoke]->GetLastUnchokeTime() < loster->GetLastUnchokeTime()) ){ // if current is empty and loser is not, loser gets 25% chance; // else loser wins. // transformed to: if loser is empty or current isn't, or 25% chance, // then loser wins. if( !peer_array[m_max_unchoke]->IsEmpty() || loster->IsEmpty() || !((rndbits>>=2)&3) ){ btPeer* tmp = peer_array[m_max_unchoke]; peer_array[m_max_unchoke] = loster; loster = tmp; } } if(loster->SetLocal(M_CHOKE) < 0){ loster->CloseConnection(); if( peer==loster ) retval = -1; } } }else //else if((btPeer*) 0 != peer_array[cancel_idx]..... peer_array[cancel_idx] = peer; return retval;}// When we change what we're going after, we need to evaluate & set our// interest with each peer appropriately.void PeerList::CheckInterest(){ PEERNODE *p = m_head; for( ; p; p = p->next ){ // Don't shortcut by checking Is_Local_Interested(), as we need to let // SetLocal() reset the m_standby flag. if( p->peer->Need_Remote_Data() ){ if( p->peer->SetLocal(M_INTERESTED) < 0 ) p->peer->CloseConnection(); }else{ if( p->peer->SetLocal(M_NOT_INTERESTED) < 0 ) p->peer->CloseConnection(); } }}btPeer* PeerList::GetNextPeer(btPeer *peer) const{ static PEERNODE *p = m_head; if( !peer ) p = m_head; else if( p && p->peer == peer ){ p = p->next; }else{ for( p=m_head; p && (p->peer != peer); p = p->next ); if(p) p = p->next; else p = m_head; } for( ; p; p = p->next ) if( p->peer && PEER_IS_SUCCESS(p->peer) ) break; if(p) return p->peer; else return (btPeer*) 0;}int PeerList::Endgame() const{ BitField tmpBitfield; tmpBitfield = *BTCONTENT.pBF; tmpBitfield.Invert(); // what I don't have... tmpBitfield.Except(BTCONTENT.GetFilter()); // ...that I want if( tmpBitfield.Count() < m_peers_count ) return 1; Pieces_I_Can_Get(&tmpBitfield); // what's available... tmpBitfield.Except(BTCONTENT.GetFilter()); // ...that I want... tmpBitfield.Except(*BTCONTENT.pBF); // ...that I don't have if( tmpBitfield.Count() < m_peers_count ) return 1; return 0;}void PeerList::Pause(){ PEERNODE *p = m_head; m_f_pause = 1; StopDownload(); for( ; p; p = p->next ){ if( p->peer->Is_Local_UnChoked() && p->peer->SetLocal(M_CHOKE) < 0 ) p->peer->CloseConnection(); }}void PeerList::Resume(){ m_f_pause = 0; CheckInterest();}void PeerList::StopDownload(){ PEERNODE *p = m_head; for( ; p; p = p->next ){ if( p->peer->Is_Local_Interested() ){ if(p->peer->PutPending() < 0 || p->peer->SetLocal(M_NOT_INTERESTED) < 0) p->peer->CloseConnection(); } }}size_t PeerList::GetUnchoked() const{ PEERNODE *p; size_t count = 0; for( p = m_head; p; p = p->next ){ if( PEER_IS_SUCCESS(p->peer) && p->peer->Is_Local_UnChoked() ){ count++; if( count > m_max_unchoke ) break; } } return count;}// This function returns 0 if it could not find an upload faster than the// minimum and all peer upload rates are known (not zero).size_t PeerList::GetSlowestUp(size_t minimum) const{ PEERNODE *p; size_t slowest = 0, zero = 0, unchoked = 0, rate; for( p = m_head; p; p = p->next ){ if( PEER_IS_SUCCESS(p->peer) && p->peer->Is_Local_UnChoked() ){ unchoked++; rate = p->peer->RateUL(); if( 0==rate ) zero = 1; else if( rate >= minimum && (rate < slowest || 0==slowest) ) slowest = rate; } } if( slowest > (rate = Self.RateUL()) ) slowest = rate; // We're looking for slow, so guess low when we must guess a rate. if( slowest ){ if( zero ) return minimum ? minimum : ((slowest+1)/2); else return slowest; }else{ if( 0==unchoked ) unchoked = 1; // safeguard if( zero ) return minimum ? minimum : ((rate = Self.RateUL()) ? rate / unchoked : 1); else return 0; }}size_t PeerList::GetDownloads() const{ PEERNODE *p; size_t count = 0; for( p = m_head; p; p = p->next ){ if( PEER_IS_SUCCESS(p->peer) && p->peer->Is_Remote_UnChoked() ) count++; } return count;}int PeerList::BandWidthLimitUp(double when) const{ double nexttime; if( cfg_max_bandwidth_up <= 0 ) return 0; nexttime = Self.LastSendTime() + (double)(Self.LastSizeSent()) / cfg_max_bandwidth_up; if( nexttime >= now + 1 + when ) return 1; else if( nexttime < now + when ) return 0; else{ struct timespec nowspec; double rightnow; clock_gettime(CLOCK_REALTIME, &nowspec); rightnow = nowspec.tv_sec + (double)(nowspec.tv_nsec)/1000000000; if( nexttime <= rightnow + when ) return 0; else return 1; }}int PeerList::BandWidthLimitDown(double when) const{ double nexttime; // Don't check SeedOnly() here--need to let the input stream drain. if( cfg_max_bandwidth_down <= 0 ) return 0; nexttime = Self.LastRecvTime() + (double)(Self.LastSizeRecv()) / cfg_max_bandwidth_down; if( nexttime >= now + 1 + when ) return 1; else if( nexttime < now + when ) return 0; else{ struct timespec nowspec; double rightnow; clock_gettime(CLOCK_REALTIME, &nowspec); rightnow = nowspec.tv_sec + (double)(nowspec.tv_nsec)/1000000000; if( nexttime <= rightnow + when ) return 0; else return 1; }}int PeerList::IsIdle() const{ return ( ( 0==cfg_max_bandwidth_down || now > (time_t)(Self.LastRecvTime() + Self.LateDL() + Self.LastSizeRecv() / (double)cfg_max_bandwidth_down) || BandWidthLimitDown(Self.LateDL()) ) && ( 0==cfg_max_bandwidth_up || now > (time_t)(Self.LastSendTime() + Self.LateUL() + Self.LastSizeSent() / (double)cfg_max_bandwidth_up) || BandWidthLimitUp(Self.LateUL()) ) );}// How long must we wait for bandwidth to become available in either direction?double PeerList::WaitBW() const{ struct timespec nowspec; double rightnow, late; double maxwait = 0, nextwake = 0; double nextup = 0, nextdn = 0; int use_up = 0, use_dn = 0; if( cfg_max_bandwidth_up ){ nextup = Self.LastSendTime() + (double)(Self.LastSizeSent()) / cfg_max_bandwidth_up; } if( cfg_max_bandwidth_down ){ nextdn = Self.LastRecvTime() + (double)(Self.LastSizeRecv()) / cfg_max_bandwidth_down; } // could optimize away the clock call when maxwait will be > MAX_SLEEP if( now <= (time_t)nextup || now <= (time_t)nextdn ){ clock_gettime(CLOCK_REALTIME, &nowspec); rightnow = nowspec.tv_sec + (double)(nowspec.tv_nsec)/1000000000; }else rightnow = (double)now; if( nextup >= rightnow ){ if( nextdn < rightnow ) use_up = 1; else if( nextdn < nextup ) use_dn = 1; else use_up = 1; }else if( nextdn >= rightnow ) use_dn = 1; if( use_up ){ nextwake = nextup; late = Self.LateUL(); }else if( use_dn ){ nextwake = nextdn; late = Self.LateDL(); }else{ nextwake = late = 0; } if( nextwake > rightnow ){ maxwait = nextwake - rightnow - late; if( maxwait < 0 ){ use_up = use_dn = 0; } Self.OntimeUL(use_up); Self.OntimeDL(use_dn); }else{ Self.OntimeUL(0); Self.OntimeDL(0); } return maxwait;}void PeerList::UnchokeIfFree(btPeer *peer){ PEERNODE *p; size_t count = 0; if( m_f_pause ) return; for( p = m_head; p; p = p->next ){ if( PEER_IS_SUCCESS(p->peer) && p->peer->Is_Local_UnChoked() && p->peer->Is_Remote_Interested() ){ count++; if( m_max_unchoke < count ) return; } } if( peer->SetLocal(M_UNCHOKE) < 0 ) peer->CloseConnection();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -