ctorrent_ipv6/peerlist.cpp

574 lines
13 KiB
C++
Raw Permalink Blame History

#include <sys/types.h>
#include "peerlist.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "btconfig.h"
#include "connect_nonb.h"
#include "setnonblock.h"
#include "btcontent.h"
#include "msgencode.h"
#include "iplist.h"
#include "tracker.h"
#define MAX_UNCHOKE 3
#define UNCHOKE_INTERVAL 10
#define KEEPALIVE_INTERVAL 117
#define LISTEN_PORT_MAX 2706
#define LISTEN_PORT_MIN 2106
#define PEER_IS_SUCCESS(peer) (P_SUCCESS == (peer)->GetStatus())
#define PEER_IS_FAILED(peer) (P_FAILED == (peer)->GetStatus())
#define NEED_MORE_PEERS() (m_peers_count < cfg_max_peers)
const char LIVE_CHAR[4] = {'-', '\\','|','/'};
PeerList WORLD;
PeerList::PeerList()
{
m_unchoke_check_timestamp =
m_keepalive_check_timestamp = time((time_t*) 0);
m_head = (PEERNODE*) 0;
m_listen_sock = INVALID_SOCKET;
m_peers_count = 0;
m_live_idx = 0;
}
PeerList::~PeerList()
{
PEERNODE *p,*pnext;
for(p = m_head; p ; ){
pnext = p->next;
delete p->peer;
delete p;
p = pnext;
}
}
int PeerList::IsEmpty() const
{
return m_peers_count ? 0 : 1;
}
void PeerList::Sort()
{
PEERNODE *newhead = (PEERNODE*) 0;
PEERNODE *p, *pp, *spn;
if( m_peers_count < 10 ) return;
for(; m_head;){
pp = (PEERNODE*) 0;
for(p = newhead; p && m_head->click < p->click; pp = p, p = p->next) ;
spn = m_head->next;
m_head->next = p;
if( pp ) pp->next = m_head; else newhead = m_head;
m_head = spn;
}
m_head = newhead;
}
void PeerList::CloseAll()
{
PEERNODE *p;
for(p = m_head; p;){
m_head = p->next;
delete (p->peer);
delete p;
p = m_head;
}
}
int PeerList::NewPeer(struct sockaddr_in6 addr, SOCKET sk)
{
PEERNODE *p;
btPeer *peer = (btPeer*) 0;
int r;
if( m_peers_count >= cfg_max_peers ){
if( INVALID_SOCKET != sk ) CLOSE_SOCKET(sk);
return -4;
}
if( Self.IpEquiv(addr) ){
if(INVALID_SOCKET != sk) CLOSE_SOCKET(sk); return -3;} // myself
for(p = m_head; p; p = p->next){
if(PEER_IS_FAILED(p->peer)) continue;
if( p->peer->IpEquiv(addr)){ // already exist.
if( INVALID_SOCKET != sk) CLOSE_SOCKET(sk);
return -3;
}
}
if( INVALID_SOCKET == sk ){
if( INVALID_SOCKET == (sk = socket(PF_INET6,SOCK_STREAM,0)) ) return -1;
if( setfd_nonblock(sk) < 0) goto err;
if( -1 == (r = connect_nonb(sk,(struct sockaddr*)&addr)) ) return -1;
peer = new btPeer;
#ifndef WINDOWS
if( !peer ) goto err;
#endif
peer->SetAddress(addr);
peer->stream.SetSocket(sk);
peer->SetStatus( (-2 == r) ? P_CONNECTING : P_HANDSHAKE );
}else{
if( setfd_nonblock(sk) < 0) goto err;
peer = new btPeer;
#ifndef WINDOWS
if( !peer ) goto err;
#endif
peer->SetAddress(addr);
peer->stream.SetSocket(sk);
peer->SetStatus(P_HANDSHAKE);
}
if( P_HANDSHAKE == peer->GetStatus() )
if( peer->Send_ShakeInfo() != 0 ) { delete peer; return -1; }
p = new PEERNODE;
#ifndef WINDOWS
if( !p ){ delete peer; return -1;}
#endif
m_peers_count++;
p->peer = peer;
p->click = 0;
p->next = m_head;
m_head = p;
return 0;
err:
CLOSE_SOCKET(sk);
return -1;
}
int PeerList::FillFDSET(const time_t *pnow,fd_set *rfdp,fd_set *wfdp)
{
PEERNODE *p;
PEERNODE *pp = (PEERNODE*) 0;
int f_keepalive_check = 0;
int f_unchoke_check = 0;
int maxfd = -1;
int i = 0;
SOCKET sk = INVALID_SOCKET;
struct sockaddr_in6 addr;
btPeer * UNCHOKER[MAX_UNCHOKE + 1];
for( ;NEED_MORE_PEERS() && !IPQUEUE.IsEmpty(); ){
if(IPQUEUE.Pop(&addr) < 0) break;
if(NewPeer(addr,INVALID_SOCKET) == -4) break;
}
// show status line.
if( m_pre_dlrate.TimeUsed(pnow) ){
printf("\r ");
printf("\r%c %u,[%u/%u/%u],%u,%u | %u,%u E:%u",
LIVE_CHAR[m_live_idx],
m_peers_count,
BTCONTENT.pBF->Count(),
BTCONTENT.pBF->NBits(),
Pieces_I_Can_Get(),
Self.RateDL(), Self.RateUL(),
m_pre_dlrate.RateMeasure(Self.GetDLRate()),
m_pre_ulrate.RateMeasure(Self.GetULRate()),
Tracker.GetRefuseClick());
fflush(stdout);
m_pre_dlrate = Self.GetDLRate();
m_pre_ulrate = Self.GetULRate();
m_live_idx++;
}
if(KEEPALIVE_INTERVAL <= (*pnow - m_keepalive_check_timestamp)){
m_keepalive_check_timestamp = *pnow;
f_keepalive_check = 1;
}
if(UNCHOKE_INTERVAL <= (*pnow - m_unchoke_check_timestamp)){
m_unchoke_check_timestamp = *pnow;
f_unchoke_check = 1;
Sort();
}
if( f_unchoke_check ) memset(UNCHOKER, 0, (MAX_UNCHOKE + 1) * sizeof(btPeer*));
for(p = m_head; p;){
if( PEER_IS_FAILED(p->peer)){
if( pp ) pp->next = p->next; else m_head = p->next;
delete p->peer;
delete p;
m_peers_count--;
if( pp ) p = pp->next; else p = m_head;
continue;
}else{
if( f_keepalive_check ){
if(3 * KEEPALIVE_INTERVAL <= (*pnow - p->peer->GetLastTimestamp())){
p->peer->CloseConnection();
goto skip_continue;
}
if(PEER_IS_SUCCESS(p->peer) &&
KEEPALIVE_INTERVAL <= (*pnow - p->peer->GetLastTimestamp()) &&
p->peer->AreYouOK() < 0){
p->peer->CloseConnection();
goto skip_continue;
}
}
if( f_unchoke_check ){
if(PEER_IS_SUCCESS(p->peer) && p->peer->Need_Local_Data()){
if((time_t) 0 == p->peer->GetLastUnchokeTime()){
if(p->peer->SetLocal(M_UNCHOKE) < 0){
p->peer->CloseConnection();
goto skip_continue;
}
}else
UnChokeCheck(p->peer, UNCHOKER);
}
}
sk = p->peer->stream.GetSocket();
if(maxfd < sk) maxfd = sk;
FD_SET(sk,rfdp);
if( p->peer->NeedWrite() ) FD_SET(sk,wfdp);
skip_continue:
pp = p;
p = p->next;
}
} // end for
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 ){
for( i = 0; i < MAX_UNCHOKE + 1; i++){
if( (btPeer*) 0 == UNCHOKER[i]) break;
if( PEER_IS_FAILED(UNCHOKER[i]) ) continue;
if( UNCHOKER[i]->SetLocal(M_UNCHOKE) < 0){
UNCHOKER[i]->CloseConnection();
continue;
}
sk = UNCHOKER[i]->stream.GetSocket();
if(!FD_ISSET(sk,wfdp) && UNCHOKER[i]->NeedWrite()){
FD_SET(sk,wfdp);
if( maxfd < sk) maxfd = sk;
}
} // end for
}
return maxfd;
}
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;
}
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;
if( 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) p->peer->CloseConnection();
}
} // end for
}
int PeerList::Accepter()
{
SOCKET newsk;
socklen_t addrlen;
struct sockaddr_in6 addr;
addrlen = sizeof(struct sockaddr_in6);
newsk = accept(m_listen_sock,(struct sockaddr*) &addr,&addrlen);
if( INVALID_SOCKET == newsk ) return -1;
if( AF_INET6 != addr.sin6_family || addrlen != sizeof(struct sockaddr_in6)) {
CLOSE_SOCKET(newsk);
return -1;
}
return NewPeer(addr,newsk);
}
int PeerList::Initial_ListenPort()
{
int r = 0;
struct sockaddr_in6 lis_addr;
memset(&lis_addr,0, sizeof(sockaddr_in6));
memcpy(&lis_addr.sin6_addr, &in6addr_any, sizeof(struct in6_addr) );
m_listen_sock = socket(PF_INET6,SOCK_STREAM,0);
if( INVALID_SOCKET == m_listen_sock ) return -1;
if(cfg_listen_port && cfg_listen_port != LISTEN_PORT_MAX){
lis_addr.sin6_port = htons(cfg_listen_port);
if(bind(m_listen_sock,(struct sockaddr*)&lis_addr,sizeof(struct sockaddr_in6)) == 0)
r = 1;
else
fprintf(stderr,"warn,couldn't bind on specified port: %d\n",cfg_listen_port);
}
if( !r ){
r = -1;
cfg_listen_port = cfg_max_listen_port;
for( ; r != 0; ){
lis_addr.sin6_port = htons(cfg_listen_port);
r = bind(m_listen_sock,(struct sockaddr*)&lis_addr,sizeof(struct sockaddr_in6));
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.\n",
cfg_min_listen_port,cfg_max_listen_port);
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.\n",cfg_listen_port);
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;
}
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( idx == p->peer->request_q.GetRequestIdx() ) return 1;
}
return 0;
}
void PeerList::CheckBitField(BitField &bf)
{
PEERNODE *p;
for(p = m_head; p ; p = p->next){
if( !PEER_IS_SUCCESS(p->peer) || p->peer->request_q.IsEmpty()) continue;
bf.UnSet(p->peer->request_q.GetRequestIdx());
}
}
void PeerList::PrintOut()
{
PEERNODE *p = m_head;
struct sockaddr_in6 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.
FD_CLR(sk,rfdp);
peer->CloseConnection();
}else{
if(peer->Send_ShakeInfo() < 0){
peer->CloseConnection();
}
else
peer->SetStatus(P_HANDSHAKE);
}
}
}else{
if(FD_ISSET(sk,rfdp)){
p->click++;
if( !(p->click) )
for(p2 = m_head; p2; p2=p2->next) p2->click = 0;
(*nready)--;
FD_CLR(sk,rfdp);
if(peer->GetStatus() == P_HANDSHAKE){
if( peer->HandShake() < 0 ) peer->CloseConnection();
}else{
if( peer->RecvModule() < 0 ) peer->CloseConnection();
}
}else if(PEER_IS_SUCCESS(peer) && FD_ISSET(sk,wfdp)){
p->click++;
if( !(p->click) )
for(p2 = m_head; p2; p2=p2->next) p2->click = 0;
(*nready)--;
FD_CLR(sk,wfdp);
if( peer->SendModule() < 0 ) peer->CloseConnection();
}
}
}// end for
}
void PeerList::CloseAllConnectionToSeed()
{
PEERNODE *p = m_head;
for( ; p; p = p->next)
if(p->peer->bitfield.IsFull()) 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();
for( cancel_idx = i = 0; i < MAX_UNCHOKE; i++ ){
if((btPeer*) 0 == peer_array[i] || PEER_IS_FAILED(peer_array[i]) ){ // <20>п<EFBFBD>λ
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())
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()){
loster = peer_array[cancel_idx];
peer_array[cancel_idx] = peer;
}else
loster = peer;
}
// opt unchoke
if((btPeer*) 0 == peer_array[MAX_UNCHOKE] || PEER_IS_FAILED(peer_array[MAX_UNCHOKE]) )
peer_array[MAX_UNCHOKE] = loster;
else{
if(loster->GetLastUnchokeTime() < peer_array[MAX_UNCHOKE]->GetLastUnchokeTime())
peer_array[MAX_UNCHOKE] = loster;
else{
if(loster->SetLocal(M_CHOKE) < 0) loster->CloseConnection();
}
}
}else //else if((btPeer*) 0 != peer_array[cancel_idx].....
peer_array[cancel_idx] = peer;
}