tracker.cpp

来自「最经典的bittorrent协议的实现的源码」· C++ 代码 · 共 615 行 · 第 1/2 页

CPP
615
字号
int btTracker::Initial(){  if(Http_url_analyse(BTCONTENT.GetAnnounce(),m_host,&m_port,m_path) < 0){    CONSOLE.Warning(1, "error, invalid tracker url format!");    return -1;  }  char chars[37] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";  for(int i=0; i<8; i++)    m_key[i] = chars[random()%36];  m_key[8] = 0;  if( BuildBaseRequest() < 0 ) return -1;  /* get local ip address */  // 1st: if behind firewall, this only gets local side  {    struct sockaddr_in addr;    socklen_t addrlen = sizeof(struct sockaddr_in);    if(getsockname(m_sock,(struct sockaddr*)&addr,&addrlen) == 0)          Self.SetIp(addr);  }  // 2nd: better to use addr of our domain  {    struct sockaddr_in addr;    struct hostent *h;    char hostname[128];    char *hostdots[2]={0,0}, *hdptr=hostname;    if (gethostname(hostname, 128) == -1) return -1;//  CONSOLE.Print("%s", hostname);    while(*hdptr) if(*hdptr++ == '.') {      hostdots[0] = hostdots[1];      hostdots[1] = hdptr;    }    if (hostdots[0] == 0) return -1;//  CONSOLE.Print("%s", hostdots[0]);    if ((h = gethostbyname(hostdots[0])) == NULL) return -1;//  CONSOLE.Print("Host domain  : %s", h->h_name);//  CONSOLE.Print("IP Address : %s", inet_ntoa(*((struct in_addr *)h->h_addr)));    memcpy(&addr.sin_addr,h->h_addr,sizeof(struct in_addr));    Self.SetIp(addr);  }  return 0;}int btTracker::BuildBaseRequest(){  char ih_buf[20 * 3 + 1], pi_buf[20 * 3 + 1], tmppath[MAXPATHLEN], *format;  strcpy(tmppath,m_path);  if(strchr(m_path, '?'))    format=REQ_URL_P1A_FMT;  else format=REQ_URL_P1_FMT;  if(MAXPATHLEN < snprintf((char*)m_path,MAXPATHLEN,format,                     tmppath,                     Http_url_encode(ih_buf,(char*)BTCONTENT.GetInfoHash(),20),                     Http_url_encode(pi_buf,(char*)BTCONTENT.GetPeerId(),20),                     cfg_listen_port,                     m_key)){    return -1;  }  return 0;}int btTracker::Connect(){  ssize_t r;  time(&m_last_timestamp);  if(_s2sin(m_host,m_port,&m_sin) < 0) {    CONSOLE.Warning(2, "warn, get tracker's ip address failed.");    return -1;  }  m_sock = socket(AF_INET,SOCK_STREAM,0);  if(INVALID_SOCKET == m_sock) return -1;  // we only need to bind if we have specified an ip  // we need it to bind here before the connect!!!!  if ( cfg_listen_ip != 0 ) {    struct sockaddr_in addr;    // clear the struct as requested in the manpages    memset(&addr,0, sizeof(sockaddr_in));    // set the type    addr.sin_family = AF_INET;    // we want the system to choose port    addr.sin_port = 0;    // set the defined ip from the commandline    addr.sin_addr.s_addr = cfg_listen_ip;    // bind it or return...    if(bind(m_sock,(struct sockaddr*)&addr,sizeof(struct sockaddr_in)) != 0){      CONSOLE.Warning(1, "warn, can't set up tracker connection:  %s",        strerror(errno));      return -1;    }  }  if(setfd_nonblock(m_sock) < 0){ CLOSE_SOCKET(m_sock); return -1; }  r = connect_nonb(m_sock,(struct sockaddr*)&m_sin);  if( r == -1 ){ CLOSE_SOCKET(m_sock); return -1; }  else if( r == -2 ) m_status = T_CONNECTING;  else{    if(arg_verbose) CONSOLE.Debug("Connected to tracker");    if( 0 == SendRequest() ) m_status = T_READY;    else{ CLOSE_SOCKET(m_sock); return -1; }  }  return 0;}int btTracker::SendRequest(){  char *event,*str_event[] = {"started","stopped","completed" };  char REQ_BUFFER[2*MAXPATHLEN];  struct sockaddr_in addr;  if( m_f_stoped )    event = str_event[1];	/* stopped */  else if( !m_f_started ){    if( BTCONTENT.IsFull() ) m_f_completed = 1;    event = str_event[0];	/* started */  }else if( BTCONTENT.IsFull() && !m_f_completed ){    if( Self.TotalDL() > 0 ) event = str_event[2];  /* download complete */    else event = (char*) 0;  /* interval */    m_f_completed = 1;		/* only send download complete once */  }else    event = (char*) 0;  /* interval */  char opt1[20] = "&event=";  char opt2[12+PEER_ID_LEN] = "&trackerid=";  if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P2_FMT,                     m_path,                     event ? strncat(opt1,event,12) : "",                     *m_trackerid ? strncat(opt2,m_trackerid,PEER_ID_LEN) : "",                     (unsigned long long)(Self.TotalUL()),                     (unsigned long long)(Self.TotalDL()),                     (unsigned long long)(BTCONTENT.GetLeftBytes()),                     (int)cfg_max_peers)){    return -1;  }  // if we have a tracker hostname (not just an IP), send a Host: header  if(_IPsin(m_host, m_port, &addr) < 0){    char REQ_HOST[MAXHOSTNAMELEN];    if(MAXHOSTNAMELEN < snprintf(REQ_HOST,MAXHOSTNAMELEN,"\r\nHost: %s",m_host))      return -1;    strcat(REQ_BUFFER, REQ_HOST);  }  strcat(REQ_BUFFER, "\r\nUser-Agent: ");  strcat(REQ_BUFFER, cfg_user_agent);  strcat(REQ_BUFFER,"\r\n\r\n");  // hc  //CONSOLE.Warning(0, "SendRequest: %s", REQ_BUFFER);  if( 0 !=      m_reponse_buffer.PutFlush(m_sock,REQ_BUFFER,strlen((char*)REQ_BUFFER)) ){    CONSOLE.Warning(2,      "warn, send request to tracker failed:  %s", strerror(errno));    if( event == str_event[2] )      m_f_completed = 0;  // failed sending completion event    return -1;  }  return 0;}int btTracker::IntervalCheck(fd_set *rfdp, fd_set *wfdp){  /* tracker communication */  if( T_FREE == m_status ){    if( INVALID_SOCKET != m_sock ){      FD_CLR(m_sock, rfdp);      FD_CLR(m_sock, wfdp);    }    if( now - m_last_timestamp >= m_interval ||        // Connect to tracker early if we run low on peers.        (WORLD.GetPeersCount() < cfg_min_peers &&          m_prevpeers >= cfg_min_peers && now - m_last_timestamp >= 15) ){      m_prevpeers = WORLD.GetPeersCount();      if(Connect() < 0){ Reset(15); return -1; }      FD_SET(m_sock, rfdp);      if( m_status == T_CONNECTING ) FD_SET(m_sock, wfdp);    }else if( now < m_last_timestamp ) m_last_timestamp = now;  }else{    if( m_status == T_CONNECTING ){      FD_SET(m_sock, rfdp);      FD_SET(m_sock, wfdp);    }else if( INVALID_SOCKET != m_sock ){      FD_SET(m_sock, rfdp);      if( m_reponse_buffer.Count() ) FD_SET(m_sock, wfdp);    }  }  return m_sock;}int btTracker::SocketReady(fd_set *rfdp, fd_set *wfdp, int *nfds,  fd_set *rfdnextp, fd_set *wfdnextp){  if( T_FREE == m_status ) return 0;  if( T_CONNECTING == m_status && FD_ISSET(m_sock,wfdp) ){    int error = 0;    socklen_t n = sizeof(error);    (*nfds)--;    FD_CLR(m_sock, wfdnextp);     if( FD_ISSET(m_sock, rfdp) ){      (*nfds)--;      FD_CLR(m_sock, rfdnextp);    }    if(getsockopt(m_sock, SOL_SOCKET,SO_ERROR,&error,&n) < 0)      error = errno;    if( error ){      if( ECONNREFUSED == error ){        if(arg_verbose) CONSOLE.Debug("tracker connection refused");        m_connect_refuse_click++;      }else CONSOLE.Warning(2,          "warn, connect to tracker failed:  %s", strerror(error));      Reset(15);      return -1;    }else{      if(arg_verbose) CONSOLE.Debug("Connected to tracker");      if( SendRequest() == 0 ) m_status = T_READY;       else { Reset(15); return -1; }    }  }else if( T_CONNECTING == m_status && FD_ISSET(m_sock,rfdp) ){    int error = 0;    socklen_t n = sizeof(error);    (*nfds)--;    FD_CLR(m_sock, rfdnextp);    if(getsockopt(m_sock, SOL_SOCKET,SO_ERROR,&error,&n) < 0)      error = errno;    CONSOLE.Warning(2, "warn, connect to tracker failed:  %s", strerror(error));    Reset(15);    return -1;  }else if( INVALID_SOCKET != m_sock ){    if( FD_ISSET(m_sock, rfdp) ){      (*nfds)--;      FD_CLR(m_sock,rfdnextp);      SOCKET tmp_sock = m_sock;      int r = CheckReponse();      if( INVALID_SOCKET == m_sock ){        if( FD_ISSET(tmp_sock, wfdp) ){          (*nfds)--;          FD_CLR(tmp_sock,wfdnextp);        }        return r;      }    }    if( FD_ISSET(m_sock, wfdp) ){      (*nfds)--;      FD_CLR(m_sock,wfdnextp);      if( m_reponse_buffer.Count() && m_reponse_buffer.FlushOut(m_sock) < 0 ){        Reset(15);        return -1;      }    }  }else{  // failsafe    Reset(15);    return -1;  }  return 0;}void btTracker::Restart(){  m_f_stoped = m_f_restart = 0;  if( T_FINISHED == m_status ){    m_status = T_FREE;    m_f_started = 0;    m_interval = 15;  }}void btTracker::SetStoped(){  if( !m_f_started ){    m_f_stoped = 1;    m_status = T_FINISHED;  }else{    Reset(1);    m_f_stoped = 1;  }}size_t btTracker::GetPeersCount() const {  // includes seeds, so must always be >= 1 (myself!)  return (m_peers_count > m_seeds_count) ? m_peers_count :           (GetSeedsCount() + (BTCONTENT.IsFull() ? 0 : 1));}size_t btTracker::GetSeedsCount() const{  return m_seeds_count ? m_seeds_count : (BTCONTENT.IsFull() ? 1 : 0);}

⌨️ 快捷键说明

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