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

📄 peerlist.cpp

📁 cTorrent advanced 3.3.2。是对 CTorrent 的一个改进版本。这是目前的最新版。
💻 CPP
📖 第 1 页 / 共 4 页
字号:
  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 && UNCHOKER ){    m_unchoke_check_timestamp = now;  // time of the last unchoke check    if (!m_opt_timestamp) m_opt_timestamp = now;    if( !UNCHOKER[0] ) Self.StopULTimer();    for( int i = 0; i < m_max_unchoke + 1; i++ ){      if( !UNCHOKER[i] ) break;      if( PEER_IS_FAILED(UNCHOKER[i]) ) continue;      sk = UNCHOKER[i]->stream.GetSocket();      if( UNCHOKER[i]->SetLocal(M_UNCHOKE) < 0 ){        if(arg_verbose) CONSOLE.Debug("close: Can't unchoke peer");        UNCHOKER[i]->CloseConnection();        FD_CLR(sk,rfdp);        FD_CLR(sk,wfdp);        continue;      }      if( !FD_ISSET(sk,wfdp) && UNCHOKER[i]->NeedWrite((int)m_f_limitu) ){        FD_SET(sk,wfdp);        if( maxfd < sk) maxfd = sk;      }    } // end for    delete []UNCHOKER;  }  return maxfd;}void PeerList::SetUnchokeIntervals(){  time_t old_unchoke_int = m_unchoke_interval, old_opt_int = m_opt_interval;  // Unchoke peers long enough to have a chance at getting some data.  if( BandWidthLimitUp() && BTCONTENT.Seeding() ){    int optx = (int)( 1 / (1 - (double)MIN_UNCHOKE_INTERVAL *                               cfg_max_bandwidth_up / cfg_req_slice_size) );    if( optx < 0 ) optx = 0;    if( optx < MIN_OPT_CYCLE ){      optx = MIN_OPT_CYCLE;      double interval = cfg_req_slice_size /           (cfg_max_bandwidth_up * MIN_OPT_CYCLE / (double)(MIN_OPT_CYCLE-1));      m_unchoke_interval = (size_t)interval;      if( interval - (int)interval > 0 ) m_unchoke_interval++;      if( m_unchoke_interval < MIN_UNCHOKE_INTERVAL )        m_unchoke_interval = MIN_UNCHOKE_INTERVAL;    }else{      // Allow each peer at least 60 seconds unchoked.      m_unchoke_interval = MIN_UNCHOKE_INTERVAL;      if( m_max_unchoke+1 < 60 / m_unchoke_interval ){        int maxopt = (int)( 1 / (1 - (double)(m_max_unchoke+1) *                                     m_unchoke_interval / 60) );        if( maxopt > MIN_OPT_CYCLE && optx > maxopt ) optx = maxopt;      }      if( optx > m_max_unchoke+2 ) optx = m_max_unchoke+2;    }    m_opt_interval = optx * m_unchoke_interval;  }else if( BandWidthLimitUp() && !BTCONTENT.Seeding() ){    // Need to be able to upload a slice per interval.    double interval = cfg_req_slice_size / (double)cfg_max_bandwidth_up;    m_unchoke_interval = (size_t)interval;    if( interval - (int)interval > 0 ) m_unchoke_interval++;    if( m_unchoke_interval < MIN_UNCHOKE_INTERVAL )      m_unchoke_interval = MIN_UNCHOKE_INTERVAL;    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;  PSLICE ps;  size_t idx;  for( p = m_head; p; p = p->next ){    if(!PEER_IS_SUCCESS(p->peer) || p->peer == proposer ||       p->peer->request_q.IsEmpty() ) continue;    if( (peer && p->peer->NominalDL() < peer->NominalDL()) ||        (!peer && p->peer->NominalDL() * 1.5 < proposer->NominalDL()) ){      idx = p->peer->request_q.GetRequestIdx();      if( proposer->bitfield.IsSet(idx) && !proposer->request_q.HasIdx(idx) )        peer = p->peer;      else{        ps = p->peer->request_q.GetHead();        for( ; ps; ps = ps->next ){          if( idx == ps->index ) continue;          idx = ps->index;          if( proposer->bitfield.IsSet(idx) &&              !proposer->request_q.HasIdx(idx) ){            peer = p->peer;            break;          }        }      }    }  } //end for  if( peer && arg_verbose )    CONSOLE.Debug("Abandoning %p (%d B/s) for %p (%d B/s)",      peer, peer->NominalDL(), proposer, proposer->NominalDL());  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, const btPeer *proposer,  size_t idx){  struct qdata {    size_t idx, qlen, count;  };  struct qdata *data;  int endgame, pass, i, mark;  PEERNODE *p;  PSLICE ps;  size_t slots, piece, qsize;  double work, best;  endgame = idx < BTCONTENT.GetNPieces();  // else initial-piece mode  slots = endgame ? BTCONTENT.GetNPieces() - BTCONTENT.pBF->Count() :                    m_downloads * 2;  if( slots < m_dup_req_pieces + 2 ) slots = m_dup_req_pieces + 2;  data = new struct qdata[slots];#ifndef WINDOWS  if( !data ) return BTCONTENT.GetNPieces();#endif  // 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();  }  // initialize  data[0].idx = BTCONTENT.GetNPieces();  data[0].qlen = 0;  data[0].count = 0;  for( i = 1; i < slots; i++ )    memcpy(data + i, data, sizeof(struct qdata));  // measure applicable piece request queues  for( p = m_head; p; p = p->next ){    if( !PEER_IS_SUCCESS(p->peer) || p->peer == proposer ||        p->peer->request_q.IsEmpty() )      continue;    piece = BTCONTENT.GetNPieces();    ps = p->peer->request_q.GetHead();    for( ; ps; ps = ps->next ){      if( piece == ps->index ||          !bf.IsSet(ps->index) || proposer->request_q.HasIdx(ps->index) )        continue;      piece = ps->index;      qsize = p->peer->request_q.Qlen(piece);      // insert queue data into array at (idx % slots)      pass = 0;      i = piece % slots;      while( data[i].idx < BTCONTENT.GetNPieces() && pass < 2 ){        if( piece == data[i].idx ) break;        i++;        if( i >= slots ){          i = 0;          pass++;        }      }      if( pass < 2 ){        if( data[i].idx == BTCONTENT.GetNPieces() ){          data[i].idx = piece;          data[i].qlen = qsize;        }        data[i].count++;      }    }  } // end of measurement loop  /* Find the best workload for initial/endgame.     In endgame mode, request the piece that should take the longest.     In initial mode, request the piece that should complete the fastest. */  best = endgame ? 0 : BTCONTENT.GetPieceLength() / cfg_req_slice_size + 2;  mark = slots;  for( i = 0; i < slots; i++ ){    if( data[i].idx == BTCONTENT.GetNPieces() ) continue;    work = data[i].qlen / (double)(data[i].count);    if( work > 1 && (endgame ? work > best : work < best) ){      best = work;      mark = i;    }  }  if( mark < slots && data[mark].count == 1 ) m_dup_req_pieces++;  CONSOLE.Debug("%d dup req pieces", (int)m_dup_req_pieces);  delete []data;  return (mark < slots) ? data[mark].idx : BTCONTENT.GetNPieces();}void PeerList::FindValuedPieces(BitField &bf, const btPeer *proposer,  int initial) const{  PEERNODE *p;  BitField bf_all_have = bf, bf_int_have = bf,    bf_others_have, bf_only_he_has = bf, *pbf_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  pbf_prefer = initial ? &bf_others_have : &bf_only_he_has;  BitField tmpBitField = bf;  tmpBitField.And(*pbf_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;}int PeerList::HasSlice(size_t idx, size_t off, size_t len) const{  PEERNODE *p;  for( p = m_head; p; p = p->next ){    if( p->peer->request_q.HasSlice(idx, off, len) )      break;  }  return p ? 1 : 0;}/* If another peer has the same slice requested first, move the proposer's   slice to the last position for the piece. */void PeerList::CompareRequest(btPeer *proposer, size_t idx){  PSLICE ps, qs;  PEERNODE *p;  size_t qlen, count=0;  ps = proposer->request_q.GetHead();  for( ; ps && idx != ps->index; ps = ps->next );  if( !ps ) return;  qlen = proposer->request_q.Qlen(idx);  do{    for( p = m_head; p; p = p->next ){      if( !PEER_IS_SUCCESS(p->peer) || p->peer->request_q.IsEmpty() ) continue;      qs = p->peer->request_q.GetHead();      for( ; qs && idx != qs->index; qs = qs->next );      if( qs && ps->index == qs->index && ps->offset == qs->offset &&          ps->length == qs->length ){        qs = ps->next;        proposer->request_q.MoveLast(ps);        ps = qs;        break;      }    }  }while( p && ++count < qlen );}int PeerList::CancelSlice(size_t idx, size_t off, size_t len){  PEERNODE *p;  int t, r=0;  for( p = m_head; p; p = p->next ){    if( !PEER_IS_SUCCESS(p->peer) ) continue;    t = p->peer->CancelSliceRequest(idx, off, len);    if( t ){      r = 1;      if( t < 0 ){        if(arg_verbose) CONSOLE.Debug("close: CancelSlice");        p->peer->CloseConnection();      }    }  }  return r;}int PeerList::CancelPiece(size_t idx){  PEERNODE *p;  int t, r=0;  for( p = m_head; p; p = p->next ){    if( !PEER_IS_SUCCESS(p->peer) ) continue;    t = p->peer->CancelPiece(idx);    if( t ){      r = 1;      if( t < 0 ){        if(arg_verbose) CONSOLE.Debug("close: CancelPiece");        p->peer->CloseConnection();      }    }  }  return r;}// Cancel one peer's request for a specific piece.void PeerList::CancelOneRequest(size_t idx){  PEERNODE *p;  PSLICE ps;  btPeer *peer = (btPeer *)0;  int count, max=0, dupcount=0, pending = 0;  if( PENDINGQUEUE.Exist(idx) ){    pending = 1;    dupcount++;  }  for( p = m_head; p; p = p->next ){    if( !PEER_IS_SUCCESS(p->peer) ) continue;    // select the peer with the most requests ahead of the target piece    count = 0;    ps = p->peer->request_q.GetHead();    for( ; ps; ps = ps->next ){      if( ps->index == idx ) break;      else count++;    }    if( ps ){      dupcount++;      // in a tie, select the slower peer      if( count > max || !peer ||          (!pending && count == max &&            p->peer->NominalDL() < peer->NominalDL()) ){        peer = p->peer;        max = count;      }    }  }  if( peer && dupcount > peer->request_q.Qlen(idx) ){    if( pending ) PENDINGQUEUE.Delete(idx);    else{      CONSOLE.Debug("Cancel #%d on %p (%d B/s)", (int)idx, peer,        (int)(peer->NominalDL()));      peer->CancelPiece(idx);    }    if( dupcount == 2 ){  // was 2, now only 1      m_dup_req_pieces--;      CONSOLE.Debug("%d dup req pieces", (int)m_dup_req_pieces);    }  }}void PeerList::RecalcDupReqs(){  PEERNODE *p;  PSLICE ps;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -