📄 peerlist.cpp
字号:
BitField tmpBitField = bf; tmpBitField.And(bf_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){ 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 + -