⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 peerlist.cpp

📁 ctorrent源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
}/* 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 + -