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

📄 peer.cpp

📁 ctorrent源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
#include "peer.h"#include <stdlib.h>#include <string.h>#include <ctype.h>#include "btstream.h"#include "./btcontent.h"#include "./msgencode.h"#include "./peerlist.h"#include "./btconfig.h"#include "bttime.h"size_t get_nl(char *sfrom){  unsigned char *from = (unsigned char *)sfrom;  size_t t;  t = (*from++) << 24;  t |= (*from++) << 16;  t |= (*from++) << 8;  t |= *from;  return t;}void set_nl(char *sto, size_t from){  unsigned char *to = (unsigned char *)sto;  *to++ = (from >> 24) & 0xff;  *to++ = (from >> 16) & 0xff;  *to++ = (from >> 8) & 0xff;  *to = from & 0xff;}// Convert a peer ID to a printable string.int TextPeerID(unsigned char *peerid, char *txtid){  int i, j;  for(i=j=0; i < PEER_ID_LEN; i++){    if( i==j && isprint(peerid[i]) && !isspace(peerid[i]) )      txtid[j++] = peerid[i];    else{      if(i==j){ sprintf(txtid+j, "0x"); j+=2; }      snprintf(txtid+j, 3, "%.2X", (int)(peerid[i]));      j += 2;    }  }  txtid[j] = '\0';  return 0;}/* g_next_up is used to rotate uploading.  If we have the opportunity to   upload to a peer but skip it due to bw limiting, the var is set to point to   that peer and it will be given priority at the next opportunity.   g_next_dn is similar, but for downloading.   g_defer_up/dn is used to let the g_next peer object know if it skipped.*/btPeer *g_next_up = (btPeer *)0;btPeer *g_next_dn = (btPeer *)0;unsigned char g_defer_up = 0;unsigned char g_defer_dn = 0;btBasic Self;void btBasic::SetCurrentRates(){  m_current_dl = rate_dl.RateMeasure();  m_current_ul = rate_ul.RateMeasure();  m_use_current = 1;}void btBasic::SetIp(struct sockaddr_in addr){  memcpy(&m_sin.sin_addr,&addr.sin_addr,sizeof(struct in_addr));}void btBasic::SetAddress(struct sockaddr_in addr){  memcpy(&m_sin,&addr,sizeof(struct sockaddr_in));}int btBasic::IpEquiv(struct sockaddr_in addr){//	fprintf(stdout,"IpEquiv: %s <=> ", inet_ntoa(m_sin.sin_addr));//	fprintf(stdout,"%s\n", inet_ntoa(addr.sin_addr));        return (memcmp(&m_sin.sin_addr,&addr.sin_addr,sizeof(struct in_addr)) == 0) ?     1 : 0;}int btPeer::Need_Local_Data(){  if( m_state.remote_interested && !bitfield.IsFull()){    if( BTCONTENT.pBF->IsFull() ) return 1; // i am seed    BitField tmpBitfield = *BTCONTENT.pBF;    tmpBitfield.Except(bitfield);    return tmpBitfield.IsEmpty() ? 0 : 1;  }  return 0;}int btPeer::Need_Remote_Data(){  if( BTCONTENT.pBF->IsFull()) return 0;  else if( bitfield.IsFull() ) return 1;  else{    BitField tmpBitfield = bitfield;    tmpBitfield.Except(*BTCONTENT.pBF);    tmpBitfield.Except(*BTCONTENT.pBFilter);    return tmpBitfield.IsEmpty() ? 0 : 1;  }  return 0;}btPeer::btPeer(){  m_f_keepalive = 0;  m_status = P_CONNECTING;  m_unchoke_timestamp = (time_t) 0;  m_last_timestamp = now;  m_state.remote_choked = m_state.local_choked = 1;  m_state.remote_interested = m_state.local_interested = 0;  m_err_count = 0;  m_cached_idx = BTCONTENT.GetNPieces();  m_standby = 0;  m_req_send = 5;  m_req_out = 0;  m_latency = 0;  m_prev_dlrate = 0;  m_health_time = m_receive_time = m_choketime = m_last_timestamp;  m_bad_health = 0;}int btPeer::SetLocal(unsigned char s){  switch(s){  case M_CHOKE:    if( m_state.local_choked ) return 0;    m_unchoke_timestamp = now;//  if(arg_verbose) fprintf(stderr, "Choking %p\n", this);    if(arg_verbose) fprintf(stderr, "Choking %p (D=%lluMB@%uK/s)\n", this,      TotalDL() >> 20, RateDL() >> 10);    m_state.local_choked = 1;     if( g_next_up == this ) g_next_up = (btPeer *)0;    if( !reponse_q.IsEmpty()) reponse_q.Empty();    break;  case M_UNCHOKE:     if( !reponse_q.IsEmpty() ) StartULTimer();    if( !m_state.local_choked ) return 0;    m_unchoke_timestamp = now;//  if(arg_verbose) fprintf(stderr, "Unchoking %p\n", this);    if(arg_verbose) fprintf(stderr, "Unchoking %p (D=%lluMB@%uK/s)\n", this,      TotalDL() >> 20, RateDL() >> 10);    m_state.local_choked = 0;    break;  case M_INTERESTED:     m_standby = 0;    if( m_state.local_interested ) return 0;    if(arg_verbose) fprintf(stderr, "Interested in %p\n", this);    m_state.local_interested = 1;    break;  case M_NOT_INTERESTED:    if( !m_state.local_interested ) return 0;    if(arg_verbose) fprintf(stderr, "Not interested in %p\n", this);    m_state.local_interested = 0;     if( !request_q.IsEmpty() ){      CancelRequest(request_q.GetHead());      request_q.Empty();    }    break;  default:    return -1;			// BUG ???  }  return stream.Send_State(s);}int btPeer::RequestPiece(){  size_t idx;  int endgame = 0;  size_t qsize = request_q.Qsize();  size_t psize = BTCONTENT.GetPieceLength() / cfg_req_slice_size;  // See if there's room in the queue for a new piece.  // Also, don't queue another piece if we still have a full piece queued.  if( cfg_req_queue_length - qsize < psize || qsize >= psize ){    m_req_send = m_req_out;   // don't come back until you receive something.    return 0;  }  if( PENDINGQUEUE.ReAssign(&request_q,bitfield) ){    if(arg_verbose) fprintf(stderr, "Assigning to %p from Pending\n", this);    return SendRequest();  }  if( m_cached_idx < BTCONTENT.GetNPieces() && !BTCONTENT.pBF->IsEmpty() ){    // A HAVE msg already selected what we want from this peer    // but ignore it in initial-piece mode.    idx = m_cached_idx;    m_cached_idx = BTCONTENT.GetNPieces();    if( !BTCONTENT.pBF->IsSet(idx) &&        !PENDINGQUEUE.Exist(idx) &&        !WORLD.AlreadyRequested(idx) ){      if(arg_verbose) fprintf(stderr, "Assigning #%u to %p\n", idx, this);      return (request_q.CreateWithIdx(idx) < 0) ? -1 : SendRequest();    }  }	// If we didn't want the cached piece, select another.  if( BTCONTENT.pBF->IsEmpty() ){    // If we don't have a complete piece yet, try to get one that's already    // in progress.  (Initial-piece mode)    BitField tmpBitField = bitfield;    idx = WORLD.What_Can_Duplicate(tmpBitField, this, BTCONTENT.GetNPieces());    if( idx < BTCONTENT.GetNPieces() ){      if(arg_verbose) fprintf(stderr, "Want to dup #%u to %p\n", idx, this);      btPeer *peer = WORLD.WhoHas(idx);      if(peer){        if(arg_verbose) fprintf( stderr, "Duping: %p to %p (#%u)\n",          peer, this, idx );        return (request_q.CopyShuffle(&peer->request_q, idx) < 0) ?          -1 : SendRequest();      }    }else if(arg_verbose) fprintf(stderr, "Nothing to dup to %p\n", this);  }	// Doesn't have a piece that's already in progress--choose another.    BitField tmpBitField;    if( bitfield.IsFull() ){      // peer is a seed      tmpBitField = *BTCONTENT.pBF;      tmpBitField.Invert();    }else{      tmpBitField = bitfield;      tmpBitField.Except(*BTCONTENT.pBF);    }    // The filter tells what we don't want.    tmpBitField.Except(*BTCONTENT.pBFilter);    // tmpBitField tells what we need from this peer...    if( !tmpBitField.IsEmpty() ){      BitField tmpBitField2 = tmpBitField;      WORLD.CheckBitField(tmpBitField2);      // [tmpBitField2]... that we haven't requested from anyone.      if(tmpBitField2.IsEmpty()){        // Everything this peer has that I want, I've already requested.        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();        if(endgame){	// OK to duplicate a request.//        idx = tmpBitField.Random();          idx = 0;	// flag for Who_Can_Duplicate()          BitField tmpBitField3 = tmpBitField2;          idx = WORLD.What_Can_Duplicate(tmpBitField3, this, idx);          if( idx < BTCONTENT.GetNPieces() ){            if(arg_verbose) fprintf(stderr,"Want to dup #%u to %p\n",idx,this);            btPeer *peer = WORLD.WhoHas(idx);            if(peer){              if(arg_verbose) fprintf( stderr, "Duping: %p to %p (#%u)\n",                peer, this, idx );              return (request_q.CopyShuffle(&peer->request_q, idx) < 0) ?                -1 : SendRequest();            }          }else if(arg_verbose) fprintf(stderr, "Nothing to dup to %p\n",this);        }else{	// not endgame mode          btPeer *peer = WORLD.Who_Can_Abandon(this); // slowest choice          if(peer){            // Cancel a request to the slowest peer & request it from this one.            if(arg_verbose) fprintf( stderr, "Reassigning %p to %p (#%u)\n",              peer, this, peer->request_q.GetRequestIdx() );            // RequestQueue class "moves" rather than "copies" in assignment!            if( request_q.Copy(&peer->request_q) < 0 ) return -1;            if(peer->CancelPiece() < 0 || peer->RequestCheck() < 0)              peer->CloseConnection();            return SendRequest();          }else{            if(arg_verbose) fprintf(stderr, "%p standby\n", this);            m_standby = 1;	// nothing to do at the moment          }        }      }else{        // Request something that we haven't requested yet (most common case).        // Try to make it something that has good trade value.        BitField tmpBitField3 = tmpBitField2;        WORLD.FindValuedPieces(tmpBitField3, this, BTCONTENT.pBF->IsEmpty());        if( tmpBitField3.IsEmpty() ) tmpBitField3 = tmpBitField2;        idx = tmpBitField3.Random();        if(arg_verbose) fprintf(stderr, "Assigning #%u to %p\n", idx, this);        return (request_q.CreateWithIdx(idx) < 0) ? -1 : SendRequest();      }    }else{      // We don't need anything from the peer.  How'd we get here?      return SetLocal(M_NOT_INTERESTED);    }  return 0;}int btPeer::MsgDeliver(){  size_t r,idx,off,len;  int retval = 0;  char *msgbuf = stream.in_buffer.BasePointer();  r = get_nl(msgbuf);  // Don't require keepalives if we're receiving other messages.  m_last_timestamp = now;  if( 0 == r ){    if( !m_f_keepalive ) if( stream.Send_Keepalive() < 0 ) return -1;    m_f_keepalive = 0;    return 0;  }else{    switch(msgbuf[4]){    case M_CHOKE:      if(H_BASE_LEN != r){ return -1;}      if(arg_verbose) fprintf(stderr, "%p choked me\n", this);      if( m_lastmsg == M_UNCHOKE && m_last_timestamp <= m_choketime+1 ){        m_err_count+=2;        if(arg_verbose) fprintf(stderr,"err: %p (%d) Choke oscillation\n",          this, m_err_count);      }      m_choketime = m_last_timestamp;      m_state.remote_choked = 1;      StopDLTimer();      if( g_next_dn == this ) g_next_dn = (btPeer *)0;      if( !request_q.IsEmpty()){        m_req_out = 0;        PENDINGQUEUE.Pending(&request_q);      }      break;    case M_UNCHOKE:      if(H_BASE_LEN != r){return -1;}      if(arg_verbose) fprintf(stderr, "%p unchoked me\n", this);      if( m_lastmsg == M_CHOKE && m_last_timestamp <= m_choketime+1 ){        m_err_count+=2;        if(arg_verbose) fprintf(stderr,"err: %p (%d) Choke oscillation\n",          this, m_err_count);      }      m_choketime = m_last_timestamp;      m_state.remote_choked = 0;      retval = RequestCheck();      break;    case M_INTERESTED:      if(H_BASE_LEN != r){return -1;}      if(arg_verbose) fprintf(stderr, "%p is interested\n", this);      m_state.remote_interested = 1;      break;

⌨️ 快捷键说明

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