📄 peerlist.cpp
字号:
}/* 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){ 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;}void PeerList::CancelSlice(size_t idx, size_t off, size_t len){ PEERNODE *p; PSLICE ps; for( p = m_head; p; p = p->next){ if( !PEER_IS_SUCCESS(p->peer) ) continue; if (p->peer->CancelSliceRequest(idx,off,len) < 0) { if(arg_verbose) fprintf(stderr, "close: CancelSlice\n"); p->peer->CloseConnection(); } }}void PeerList::Tell_World_I_Have(size_t idx){ PEERNODE *p; int f_seed = 0; if ( BTCONTENT.pBF->IsFull() ) f_seed = 1; for( p = m_head; p; p = p->next){ if( !PEER_IS_SUCCESS(p->peer) ) continue; // Don't send HAVE to seeders, except for our first piece. if( (!p->peer->bitfield.IsFull() || 1==BTCONTENT.pBF->Count()) && p->peer->stream.Send_Have(idx) < 0) p->peer->CloseConnection(); if( f_seed ){ if( !p->peer->request_q.IsEmpty() ) p->peer->request_q.Empty(); if(p->peer->SetLocal(M_NOT_INTERESTED) < 0) { if(arg_verbose) fprintf(stderr, "close: Can't set self not interested (T_W_I_H)\n"); p->peer->CloseConnection(); } } } // end for}int PeerList::Accepter(){ SOCKET newsk; socklen_t addrlen; struct sockaddr_in addr; addrlen = sizeof(struct sockaddr_in); newsk = accept(m_listen_sock,(struct sockaddr*) &addr,&addrlen); if( INVALID_SOCKET == newsk ) return -1; if( AF_INET != addr.sin_family || addrlen != sizeof(struct sockaddr_in)) { CLOSE_SOCKET(newsk); return -1; } if( Tracker.IsPaused() || Tracker.IsQuitting() ){ CLOSE_SOCKET(newsk); return -1; } return NewPeer(addr,newsk);}int PeerList::Initial_ListenPort(){ int r = 0; struct sockaddr_in lis_addr; memset(&lis_addr,0, sizeof(sockaddr_in)); lis_addr.sin_family = AF_INET; lis_addr.sin_addr.s_addr = INADDR_ANY; m_listen_sock = socket(AF_INET,SOCK_STREAM,0); if( INVALID_SOCKET == m_listen_sock ) return -1; if ( cfg_listen_ip != 0 ) lis_addr.sin_addr.s_addr = cfg_listen_ip; if(cfg_listen_port && cfg_listen_port != LISTEN_PORT_MAX){ lis_addr.sin_port = htons(cfg_listen_port); if(bind(m_listen_sock,(struct sockaddr*)&lis_addr,sizeof(struct sockaddr_in)) == 0) r = 1; else fprintf(stderr,"warn,couldn't bind on specified port %d: %s\n", cfg_listen_port,strerror(errno)); } if( !r ){ r = -1; cfg_listen_port = cfg_max_listen_port; for( ; r != 0; ){ lis_addr.sin_port = htons(cfg_listen_port); r = bind(m_listen_sock,(struct sockaddr*)&lis_addr,sizeof(struct sockaddr_in)); if(r != 0){ cfg_listen_port--; if(cfg_listen_port < cfg_min_listen_port){ CLOSE_SOCKET(m_listen_sock); fprintf(stderr,"error,couldn't bind port from %d to %d: %s\n", cfg_min_listen_port,cfg_max_listen_port,strerror(errno)); return -1; } } } /* end for(; r != 0;) */ } if(listen(m_listen_sock,5) == -1){ CLOSE_SOCKET(m_listen_sock); fprintf(stderr,"error, couldn't listen on port %d: %s\n", cfg_listen_port,strerror(errno)); return -1; } if( setfd_nonblock(m_listen_sock) < 0){ CLOSE_SOCKET(m_listen_sock); fprintf(stderr,"error, couldn't set socket to nonblock mode.\n"); return -1; } printf("Listening on %s:%d\n", inet_ntoa(lis_addr.sin_addr), ntohs(lis_addr.sin_port)); return 0;}size_t PeerList::Pieces_I_Can_Get(){ PEERNODE *p; BitField tmpBitField = *BTCONTENT.pBF; if( tmpBitField.IsFull() ) return BTCONTENT.GetNPieces(); for( p = m_head; p && !tmpBitField.IsFull(); p = p->next){ if( !PEER_IS_SUCCESS(p->peer) ) continue; tmpBitField.Comb(p->peer->bitfield); } return tmpBitField.Count();}int PeerList::AlreadyRequested(size_t idx){ PEERNODE *p; for(p = m_head; p; p = p->next){ if( !PEER_IS_SUCCESS(p->peer) || p->peer->request_q.IsEmpty()) continue; if( p->peer->request_q.HasIdx(idx) ) return 1; } return 0;}void PeerList::CheckBitField(BitField &bf){ PEERNODE *p; PSLICE ps; size_t idx; for(p = m_head; p ; p = p->next){ if( !PEER_IS_SUCCESS(p->peer) || p->peer->request_q.IsEmpty()) continue; ps = p->peer->request_q.GetHead(); idx = BTCONTENT.GetNPieces(); for( ; ps; ps = ps->next){ if( ps->index != idx ){ bf.UnSet(ps->index); idx = ps->index; } } }}void PeerList::PrintOut(){ PEERNODE *p = m_head; struct sockaddr_in sin; printf("\nPEER LIST\n"); for( ; p ; p = p->next){ if(PEER_IS_FAILED(p->peer)) continue; p->peer->dump(); }}void PeerList::AnyPeerReady(fd_set *rfdp, fd_set *wfdp, int *nready){ PEERNODE *p,*p2; btPeer *peer; SOCKET sk; if( FD_ISSET(m_listen_sock, rfdp)){ FD_CLR(m_listen_sock,rfdp); (*nready)--; Accepter(); } for(p = m_head; p && *nready ; p = p->next){ if( PEER_IS_FAILED(p->peer) ) continue; peer = p->peer; sk = peer->stream.GetSocket(); if( P_CONNECTING == peer->GetStatus()){ if(FD_ISSET(sk,wfdp)){ (*nready)--; FD_CLR(sk,wfdp); if(FD_ISSET(sk,rfdp)){ // connect failed. (*nready)--; FD_CLR(sk,rfdp); peer->CloseConnection(); }else{ if(peer->Send_ShakeInfo() < 0){ if(arg_verbose) fprintf(stderr, "close: Sending handshake\n"); peer->CloseConnection(); } else peer->SetStatus(P_HANDSHAKE); } }else if(FD_ISSET(sk,rfdp)){ (*nready)--; peer->CloseConnection(); } }else{ if(FD_ISSET(sk,rfdp)){ (*nready)--; FD_CLR(sk,rfdp); if(peer->GetStatus() == P_HANDSHAKE){ if( peer->HandShake() < 0 ) { if(arg_verbose) fprintf(stderr, "close: bad handshake\n"); peer->CloseConnection(); } } // fixed client stall if(peer->GetStatus() == P_SUCCESS){ if( peer->RecvModule() < 0 ) { if(arg_verbose) fprintf(stderr, "close: receive\n"); peer->CloseConnection(); } } }else if( peer->HealthCheck(now) < 0 ){ if(arg_verbose) fprintf(stderr, "close: unresponsive\n"); peer->CloseConnection(); } if( (PEER_IS_SUCCESS(peer) || peer->GetStatus() == P_HANDSHAKE) && FD_ISSET(sk,wfdp) ){ (*nready)--; FD_CLR(sk,wfdp); if( peer->SendModule() < 0 ) { if(arg_verbose) fprintf(stderr, "close: send\n"); peer->CloseConnection(); } }else peer->CheckSendStatus(); } }// end for}void PeerList::CloseAllConnectionToSeed(){ PEERNODE *p = m_head; for( ; p; p = p->next) if(p->peer->bitfield.IsFull()) { if(arg_verbose) fprintf(stderr, "close: seed<->seed\n"); p->peer->CloseConnection(); }}void PeerList::UnChokeCheck(btPeer* peer, btPeer *peer_array[]){ int i = 0; int cancel_idx = 0; btPeer *loster = (btPeer*) 0; int f_seed = BTCONTENT.pBF->IsFull(); int no_opt = 0; unsigned long rndbits; int r=0; if (m_opt_timestamp) no_opt = 1;// Find my 3 or 4 fastest peers.// The 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 < 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 upload rate. if(peer_array[cancel_idx]->RateUL() > peer_array[i]->RateUL()) 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->RateUL() > peer_array[cancel_idx]->RateUL()){ 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(); } else // The last slot is for the optimistic unchoke. if( (btPeer*) 0 == peer_array[MAX_UNCHOKE] || PEER_IS_FAILED(peer_array[MAX_UNCHOKE]) ) peer_array[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[MAX_UNCHOKE]->IsEmpty() && (rndbits>>=2)&3 ) { btPeer* tmp = peer_array[MAX_UNCHOKE]; peer_array[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[MAX_UNCHOKE]->Is_Local_UnChoked() || loster->GetLastUnchokeTime() < peer_array[MAX_UNCHOKE]->GetLastUnchokeTime() )) || (peer_array[MAX_UNCHOKE]->Is_Local_UnChoked() && peer_array[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[MAX_UNCHOKE]->IsEmpty() || loster->IsEmpty() || !((rndbits>>=2)&3) ) { btPeer* tmp = peer_array[MAX_UNCHOKE]; peer_array[MAX_UNCHOKE] = loster; loster = tmp; } } if(loster->SetLocal(M_CHOKE) < 0) loster->CloseConnection(); } }else //else if((btPeer*) 0 != peer_array[cancel_idx]..... peer_array[cancel_idx] = peer;}// 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){ static PEERNODE *p = m_head; if( 0==peer ) p = m_head; else if( p->peer == peer ){ p = p->next; }else{ for( p=m_head; p && (p->peer != peer); p = p->next); if( 0 == p->peer ){ p = m_head; }else{ p = p->next; } } for( ; p; p = p->next) if( p->peer && PEER_IS_SUCCESS(p->peer) ) break; if(p) return p->peer; else return (btPeer*) 0;}// This is used to un-standby peers when we enter endgame mode.// It re-evaluates at most once per second for CPU efficiency, so isn't used// when greatest accuracy is desired.int PeerList::Endgame(){ static time_t timestamp = 0; static int endgame = 0; if( now > timestamp ){ timestamp = now; if( arg_file_to_download ){ BitField afdBitField = *BTCONTENT.pBF; afdBitField.Except(*BTCONTENT.pBFilter); endgame = ( BTCONTENT.getFilePieces(arg_file_to_download) - afdBitField.Count() ) < WORLD.TotalPeers(); }else endgame = ( WORLD.Pieces_I_Can_Get() - BTCONTENT.pBF->Count() ) < WORLD.TotalPeers(); } return endgame;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -