📄 peerlist.cpp
字号:
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; for( p = m_head; p; p = p->next ){ if(!PEER_IS_SUCCESS(p->peer) || p->peer == proposer || p->peer->request_q.IsEmpty() ) continue; if(proposer->bitfield.IsSet(p->peer->request_q.GetRequestIdx())){ if(!peer){ if( p->peer->RateDL() < proposer->RateDL() ) peer = p->peer; }else{ if( p->peer->RateDL() < peer->RateDL() ) peer = p->peer; } } }//end for 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, btPeer *proposer, size_t idx)const{ PEERNODE *p; btPeer *peer = (btPeer*) 0; int endgame; PSLICE ps; size_t piece, piece1, qsize, mark, bench; unsigned long rndbits; int r=0; endgame = idx < BTCONTENT.GetNPieces(); // else initial-piece mode if(endgame) mark = 0; else mark = cfg_req_queue_length; bench = BTCONTENT.GetNPieces(); // 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(); } /* In endgame mode, select from peers with the longest request queue. In initial mode, select from peers with the shortest non-empty request queue. */ piece1 = BTCONTENT.GetNPieces(); for( p = m_head; p; p = p->next ){ if( !PEER_IS_SUCCESS(p->peer) || p->peer == proposer ) continue; if( p->peer->request_q.IsEmpty() ) continue; piece = BTCONTENT.GetNPieces(); ps = p->peer->request_q.GetHead(); for( ; ps; ps = ps->next ){ if( piece == ps->index || bench == ps->index || piece1 == ps->index || !bf.IsSet(ps->index) || proposer->request_q.HasIdx(ps->index) ) continue; piece = ps->index; qsize = p->peer->request_q.Qlen(piece); if( (endgame && qsize > mark) || (!endgame && (qsize < mark || !peer)) ){ mark = qsize; peer = p->peer; piece1 = piece; }else if( qsize == mark ){ if( !r-- ){ rndbits = random(); r = 30; } if( bench != piece && (rndbits>>=1)&01 ){ bench = piece1; peer = p->peer; piece1 = piece; } } } } return peer ? piece1 : BTCONTENT.GetNPieces();}void PeerList::FindValuedPieces(BitField &bf, btPeer *proposer, int initial)const{ PEERNODE *p; BitField bf_all_have = bf, bf_int_have = bf, bf_others_have, bf_only_he_has = bf, bf_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 bf_prefer = initial ? bf_others_have : bf_only_he_has; 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) 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;}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) CONSOLE.Debug("close: CancelSlice"); p->peer->CloseConnection(); } }}void PeerList::CancelPiece(size_t idx){ PEERNODE *p; PSLICE ps; for( p = m_head; p; p = p->next ){ if( !PEER_IS_SUCCESS(p->peer) ) continue; if( p->peer->CancelPiece(idx) < 0 ){ if(arg_verbose) CONSOLE.Debug("close: CancelPiece"); p->peer->CloseConnection(); } }}void PeerList::Tell_World_I_Have(size_t idx){ PEERNODE *p; int f_seed = 0; if ( BTCONTENT.Seeding() ) 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(); else if( f_seed ){ // request queue is emptied by setting not-interested state if( p->peer->SetLocal(M_NOT_INTERESTED) < 0 ){ if(arg_verbose) CONSOLE.Debug("close: Can't set self not interested (T_W_I_H)"); 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.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; strcpy(m_listen, "n/a"); 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){ 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 CONSOLE.Warning(2, "warn, couldn't bind on specified port %d: %s", cfg_listen_port, strerror(errno)); } if( !r && (!cfg_listen_port || cfg_listen_port > 1025) ){ r = -1; if(cfg_listen_port){ cfg_min_listen_port = cfg_listen_port - (cfg_max_listen_port - cfg_min_listen_port); if( cfg_min_listen_port < 1025 ) cfg_min_listen_port = 1025; cfg_max_listen_port = cfg_listen_port; } 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); CONSOLE.Warning(1, "error, couldn't bind port from %d to %d: %s", 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); CONSOLE.Warning(1, "error, couldn't listen on port %d: %s", cfg_listen_port,strerror(errno)); return -1; } if( setfd_nonblock(m_listen_sock) < 0){ CLOSE_SOCKET(m_listen_sock); CONSOLE.Warning(1, "error, couldn't set socket to nonblock mode."); return -1; } snprintf(m_listen, sizeof(m_listen), "%s:%d", inet_ntoa(lis_addr.sin_addr), ntohs(lis_addr.sin_port)); CONSOLE.Print("Listening on %s", m_listen); return 0;}size_t PeerList::Pieces_I_Can_Get() const{ BitField tmpBitField; return Pieces_I_Can_Get(&tmpBitField);}size_t PeerList::Pieces_I_Can_Get(BitField *ptmpBitField) const{ if( m_seeds_count > 0 || BTCONTENT.IsFull() ) ptmpBitField->SetAll(); else{ PEERNODE *p; *ptmpBitField = *BTCONTENT.pBF; for( p = m_head; p && !ptmpBitField->IsFull(); p = p->next ){ if( PEER_IS_SUCCESS(p->peer) ) ptmpBitField->Comb(p->peer->bitfield); } } return ptmpBitField->Count();}int PeerList::AlreadyRequested(size_t idx) const{ 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() const{ PEERNODE *p = m_head; struct sockaddr_in sin; CONSOLE.Print("PEER LIST"); 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, fd_set *rfdnextp, fd_set *wfdnextp){ PEERNODE *p,*p2; btPeer *peer; SOCKET sk; int need_check_send = 0; if( FD_ISSET(m_listen_sock, rfdp) ){ (*nready)--; if( !Self.OntimeDL() && !Self.OntimeUL() ){ FD_CLR(m_listen_sock,rfdnextp); Accepter(); } } for( p = m_head; p && (*nready || need_check_send) ; p = p->next ){ if( PEER_IS_FAILED(p->peer) ) continue; peer = p->peer; sk = peer->stream.GetSocket(); if( P_SUCCESS == peer->GetStatus() && FD_ISSET(sk,rfdp) ){ (*nready)--; if( !Self.OntimeUL() ){ FD_CLR(sk,rfdnextp); if( peer->RecvModule() < 0 ){ if(arg_verbose) CONSOLE.Debug("close: receive"); peer->CloseConnection(); }else if( !Self.OntimeDL() && peer->HealthCheck() < 0 ){ if(arg_verbose) CONSOLE.Debug("close: unhealthy"); peer->CloseConnection(); } if( PEER_IS_FAILED(peer) && FD_ISSET(sk,wfdp) ){ (*nready)--; FD_CLR(sk,wfdnextp); } } } if( P_SUCCESS == peer->GetStatus() ){ if( FD_ISSET(sk,wfdp) ){ (*nready)--; if( !Self.OntimeDL() ){ FD_CLR(sk,wfdnextp); if( peer->SendModule() < 0 ){ if(arg_verbose) CONSOLE.Debug("close: send"); peer->CloseConnection(); } need_check_send = 1; } }else if( !Self.OntimeDL() ) need_check_send = (peer->CheckSendStatus() && need_check_send); } else if( P_HANDSHAKE == peer->GetStatus() ){ if( FD_ISSET(sk,rfdp) ){ (*nready)--; if( !Self.OntimeDL() && !Self.OntimeUL() ){ FD_CLR(sk,rfdnextp); if( peer->HandShake() < 0 ){ if(arg_verbose) CONSOLE.Debug("close: bad handshake"); peer->CloseConnection(); } } } if( FD_ISSET(sk,wfdp) ){ (*nready)--; if( !Self.OntimeDL() && !Self.OntimeUL() ){ FD_CLR(sk,wfdnextp); if( peer->SendModule() < 0 ){ if(arg_verbose) CONSOLE.Debug("close: send handshake"); peer->CloseConnection(); } } } } else if( P_CONNECTING == peer->GetStatus() ){ if( FD_ISSET(sk,rfdp) ){ // connect failed. (*nready)--; if( FD_ISSET(sk,wfdp) ){ (*nready)--; FD_CLR(sk,wfdnextp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -