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

📄 peerlist.cpp

📁 最经典的bittorrent协议的实现的源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
    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 + -