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 + -
显示快捷键?