15 #include "httpencode.h"
17 #include "setnonblock.h"
18 #include "connect_nonb.h"
19 #include "btcontent.h"
26 btTracker::btTracker()
28 memset(m_host,0,MAXHOSTNAMELEN);
29 memset(m_path,0,MAXPATHLEN);
31 m_sock = INVALID_SOCKET;
34 m_f_started = m_f_stoped = m_f_pause = 0;
37 m_connect_refuse_click = 0;
38 m_last_timestamp = (time_t) 0;
41 btTracker::~btTracker()
43 if( m_sock != INVALID_SOCKET) CLOSE_SOCKET(m_sock);
46 void btTracker::Reset(time_t new_interval)
48 if(new_interval) m_interval = new_interval;
50 if( INVALID_SOCKET != m_sock ){
52 m_sock = INVALID_SOCKET;
55 m_reponse_buffer.Reset();
56 time(&m_last_timestamp);
60 int btTracker:: _IPsin(char *h, int p, struct sockaddr_in *psin)
62 psin->sin_family = AF_INET;
63 psin->sin_port = htons(p);
64 psin->sin_addr.s_addr = inet_addr(h);
65 return ( psin->sin_addr.s_addr == INADDR_NONE ) ? -1 : 0;
68 int btTracker:: _s2sin(char *h,int p,struct sockaddr_in *psin)
70 psin->sin_family = AF_INET;
71 psin->sin_port = htons(p);
73 psin->sin_addr.s_addr = inet_addr(h);
74 if(psin->sin_addr.s_addr == INADDR_NONE){
75 struct hostent *ph = gethostbyname(h);
76 if( !ph || ph->h_addrtype != AF_INET){
77 memset(psin,0,sizeof(struct sockaddr_in));
80 memcpy(&psin->sin_addr,ph->h_addr_list[0],sizeof(struct in_addr));
83 psin->sin_addr.s_addr = htonl(INADDR_ANY);
87 int btTracker::_UpdatePeerList(char *buf,size_t bufsiz)
89 char tmphost[MAXHOSTNAMELEN];
94 struct sockaddr_in addr;
96 if( decode_query(buf,bufsiz,"failure reason",&ps,&i,QUERY_STR) ){
97 char failreason[1024];
99 memcpy(failreason, ps, i);
100 failreason[i] = '\0';
102 memcpy(failreason, ps, 1000);
103 failreason[1000] = '\0';
104 strcat(failreason,"...");
106 fprintf(stderr,"TRACKER FAILURE REASON: %s\n",failreason);
110 if(!decode_query(buf,bufsiz,"interval",(const char**) 0,&i,QUERY_INT)){return -1;}
112 if(m_interval != (time_t)i) m_interval = (time_t)i;
114 pos = decode_query(buf,bufsiz,"peers",(const char**) 0,(size_t *) 0,QUERY_POS);
120 if(4 > bufsiz - pos){return -1; } // peers list ̫С
122 buf += (pos + 1); bufsiz -= (pos + 1);
124 for( ;bufsiz && *buf!='e'; buf += pos, bufsiz -= pos ){
125 pos = decode_dict(buf,bufsiz,(char*) 0);
127 if(!decode_query(buf,pos,"ip",&ps,&i,QUERY_STR) || MAXHOSTNAMELEN < i) continue;
128 memcpy(tmphost,ps,i); tmphost[i] = '\0';
130 if(!decode_query(buf,pos,"port",(const char**) 0,&tmpport,QUERY_INT)) continue;
132 if(!decode_query(buf,pos,"peer id",&ps,&i,QUERY_STR) || i != 20 ) continue;
134 if(_IPsin(tmphost,tmpport,&addr) < 0){
135 fprintf(stderr,"warn, delected invalid ip address %s.\n",tmphost);
139 if( !Self.IpEquiv(addr) ){
145 if( !cnt ) fprintf(stderr,"warn, peers list recved from tracker is empty.\n");
150 int btTracker::CheckReponse()
152 #define MAX_LINE_SIZ 32
155 size_t q, hlen, dlen;
157 r = m_reponse_buffer.FeedIn(m_sock);
159 if( r > 0 ) return 0;
161 q = m_reponse_buffer.Count();
163 Reset( (-1 == r) ? 15 : 0 );
167 socklen_t n = sizeof(error);
168 if(getsockopt(m_sock, SOL_SOCKET,SO_ERROR,&error,&n) < 0 ||
170 fprintf(stderr,"warn, recved nothing from tracker! %s\n",strerror(error));
175 hlen = Http_split(m_reponse_buffer.BasePointer(), q, &pdata,&dlen);
178 fprintf(stderr,"warn, tracker reponse invalid. no html header found.\n");
182 r = Http_reponse_code(m_reponse_buffer.BasePointer(),hlen);
184 if( r == 301 || r == 302 ){
185 char redirect[MAXPATHLEN],ih_buf[20 * 3 + 1],pi_buf[20 * 3 + 1],tmppath[MAXPATHLEN];
186 if( Http_get_header(m_reponse_buffer.BasePointer(), hlen, "Location", redirect) < 0 )
189 if( Http_url_analyse(redirect,m_host,&m_port,m_path) < 0){
190 fprintf(stderr,"warn, tracker redirect to a invalid url %s!\n", redirect);
194 strcpy(tmppath,m_path);
196 if(MAXPATHLEN < snprintf(m_path,MAXPATHLEN,REQ_URL_P1_FMT,
198 Http_url_encode(ih_buf, (char*)BTCONTENT.GetInfoHash(), 20),
199 Http_url_encode(pi_buf, (char*)BTCONTENT.GetPeerId(), 20),
205 }else if( r >= 400 ){
206 fprintf(stderr,"\nTracker reponse code >= 400 !!! Maybe file not register on this tracker or it so old that have been removed from this tracker, IF YOU SEE THIS MESSAGE FOR A LONG TIME AND DOWNLOAD HAVEN'T BEGIN, RECOMMEND YOU STOP NOW!!!\n");
207 fprintf(stderr,"\nTracker reponse data DUMP:\n");
208 if( pdata && dlen ) write(STDERR_FILENO, pdata, dlen);
209 fprintf(stderr,"\n== DUMP OVER==\n");
215 if ( !pdata ) return 0;
217 if( !m_f_started ) m_f_started = 1;
218 m_connect_refuse_click = 0;
220 return _UpdatePeerList(pdata,dlen);
223 int btTracker::Initial()
225 char ih_buf[20 * 3 + 1],pi_buf[20 * 3 + 1],tmppath[MAXPATHLEN];
227 if(Http_url_analyse(BTCONTENT.GetAnnounce(),m_host,&m_port,m_path) < 0){
228 fprintf(stderr,"error, invalid tracker url format!\n");
232 strcpy(tmppath,m_path);
234 if(MAXPATHLEN < snprintf((char*)m_path,MAXPATHLEN,REQ_URL_P1_FMT,
236 Http_url_encode(ih_buf,(char*)BTCONTENT.GetInfoHash(),20),
237 Http_url_encode(pi_buf,(char*)BTCONTENT.GetPeerId(),20),
244 int btTracker::Connect()
247 time(&m_last_timestamp);
249 if(_s2sin(m_host,m_port,&m_sin) < 0) {
250 fprintf(stderr,"warn, get tracker's ip address failed.");
254 m_sock = socket(AF_INET,SOCK_STREAM,0);
255 if(INVALID_SOCKET == m_sock) return -1;
257 if(setfd_nonblock(m_sock) < 0) {CLOSE_SOCKET(m_sock); return -1; }
259 r = connect_nonb(m_sock,(struct sockaddr*)&m_sin);
261 if( r == -1 ){ CLOSE_SOCKET(m_sock); return -1;}
262 else if( r == -2 ) m_status = T_CONNECTING;
264 if( 0 == SendRequest()) m_status = T_READY;
265 else{ CLOSE_SOCKET(m_sock); return -1;}
270 int btTracker::SendRequest()
272 char *event,*str_event[] = {"started","stopped","completed" };
273 char REQ_BUFFER[MAXPATHLEN];
276 struct sockaddr_in addr;
277 addrlen = sizeof(struct sockaddr_in);
279 /* get local ip address */
280 if(getsockname(m_sock,(struct sockaddr*)&addr,&addrlen) < 0){ return -1;}
284 if( m_f_stoped ) /* stoped */
285 event = str_event[1];
286 else if( BTCONTENT.pBF->IsFull()) /* download complete */
287 event = str_event[2];
288 else if( m_f_started ) /* interval */
291 event = str_event[0]; /* started */
294 if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P2_FMT,
296 (size_t)Self.TotalUL(),
297 (size_t)Self.TotalDL(),
298 (size_t)BTCONTENT.GetLeftBytes(),
303 if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P3_FMT,
305 (size_t)Self.TotalUL(),
306 (size_t)Self.TotalDL(),
307 (size_t)BTCONTENT.GetLeftBytes()
313 if(_IPsin(m_host, m_port, &addr) < 0){
314 char REQ_HOST[MAXHOSTNAMELEN];
315 if(MAXHOSTNAMELEN < snprintf(REQ_HOST,MAXHOSTNAMELEN,"\r\nHost: %s",m_host)) return -1;
316 strcat(REQ_BUFFER, REQ_HOST);
319 strcat(REQ_BUFFER,"\r\n\r\n");
321 if( 0 != m_reponse_buffer.PutFlush(m_sock,REQ_BUFFER,strlen((char*)REQ_BUFFER))){
322 fprintf(stderr,"warn, send request to tracker failed. %s\n",strerror(errno));
329 int btTracker::IntervalCheck(const time_t *pnow, fd_set *rfdp, fd_set *wfdp)
331 /* tracker communication */
332 if( T_FREE == m_status ){
333 if((*pnow - m_last_timestamp >= m_interval) &&
334 (cfg_min_peers > WORLD.TotalPeers())){
336 if(Connect() < 0){ Reset(15); return -1; }
338 if( m_status == T_CONNECTING ){
339 FD_SET(m_sock, rfdp);
340 FD_SET(m_sock, wfdp);
342 FD_SET(m_sock, rfdp);
346 if( m_status == T_CONNECTING ){
347 FD_SET(m_sock, rfdp);
348 FD_SET(m_sock, wfdp);
350 FD_SET(m_sock, rfdp);
356 int btTracker::SocketReady(fd_set *rfdp, fd_set *wfdp, int *nfds)
358 if( T_FREE == m_status ) return 0;
360 if( T_CONNECTING == m_status &&
361 (FD_ISSET(m_sock, wfdp) || FD_ISSET(m_sock,wfdp)) ){
363 socklen_t n = sizeof(error);
365 FD_CLR(m_sock, wfdp);
366 if(getsockopt(m_sock, SOL_SOCKET,SO_ERROR,&error,&n) < 0 ||
368 if( ECONNREFUSED != error )
369 fprintf(stderr,"warn, connect to tracker failed. %s\n",strerror(error));
371 m_connect_refuse_click++;
375 if( SendRequest() == 0 ) m_status = T_READY;
376 else { Reset(15); return -1; }
378 }else if(FD_ISSET(m_sock, rfdp) ){