OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / ctorrent / tracker.cpp
1 #include "tracker.h"
2
3 #ifndef WINDOWS
4 #include <unistd.h>
5 #include <sys/time.h>
6 #include <time.h>
7 #include <netdb.h>
8 #endif
9
10 #include <stdlib.h>
11 #include <string.h>
12 #include <errno.h>
13
14 #include "peerlist.h"
15 #include "httpencode.h"
16 #include "bencode.h"
17 #include "setnonblock.h"
18 #include "connect_nonb.h"
19 #include "btcontent.h"
20 #include "iplist.h"
21
22 #include "btconfig.h"
23
24 btTracker Tracker;
25
26 btTracker::btTracker()
27 {
28   memset(m_host,0,MAXHOSTNAMELEN);
29   memset(m_path,0,MAXPATHLEN);
30
31   m_sock = INVALID_SOCKET;
32   m_port = 80;
33   m_status = T_FREE;
34   m_f_started = m_f_stoped = m_f_pause = 0;
35   m_interval = 15;
36
37   m_connect_refuse_click = 0;
38   m_last_timestamp = (time_t) 0;
39 }
40
41 btTracker::~btTracker()
42 {
43   if( m_sock != INVALID_SOCKET) CLOSE_SOCKET(m_sock);
44 }
45
46 void btTracker::Reset(time_t new_interval)
47 {
48   if(new_interval) m_interval = new_interval;
49   
50   if( INVALID_SOCKET != m_sock ){
51     CLOSE_SOCKET(m_sock);
52     m_sock = INVALID_SOCKET;
53   }
54   
55   m_reponse_buffer.Reset();
56   time(&m_last_timestamp);
57   m_status = T_FREE;
58 }
59
60 int btTracker:: _IPsin(char *h, int p, struct sockaddr_in *psin)
61 {
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;
66 }
67
68 int btTracker:: _s2sin(char *h,int p,struct sockaddr_in *psin)
69 {
70   psin->sin_family = AF_INET;
71   psin->sin_port = htons(p);
72   if( h ){
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));
78         return -1;
79       }
80       memcpy(&psin->sin_addr,ph->h_addr_list[0],sizeof(struct in_addr));
81     }
82   }else 
83     psin->sin_addr.s_addr = htonl(INADDR_ANY);
84   return 0;
85 }
86
87 int btTracker::_UpdatePeerList(char *buf,size_t bufsiz)
88 {
89   char tmphost[MAXHOSTNAMELEN];
90   const char *ps;
91   size_t i,pos,tmpport;
92   size_t cnt = 0;
93
94   struct sockaddr_in addr;
95
96   if( decode_query(buf,bufsiz,"failure reason",&ps,&i,QUERY_STR) ){
97     char failreason[1024];
98     if( i < 1024 ){
99       memcpy(failreason, ps, i);
100       failreason[i] = '\0';
101     }else{
102       memcpy(failreason, ps, 1000);
103       failreason[1000] = '\0';
104       strcat(failreason,"...");
105     }
106     fprintf(stderr,"TRACKER FAILURE REASON: %s\n",failreason);
107     return -1;
108   }
109
110   if(!decode_query(buf,bufsiz,"interval",(const char**) 0,&i,QUERY_INT)){return -1;}
111
112   if(m_interval != (time_t)i) m_interval = (time_t)i;
113
114   pos = decode_query(buf,bufsiz,"peers",(const char**) 0,(size_t *) 0,QUERY_POS);
115
116   if( !pos ){
117     return -1;
118   }
119
120   if(4 > bufsiz - pos){return -1; } // peers list ̫С
121
122   buf += (pos + 1); bufsiz -= (pos + 1);
123
124   for( ;bufsiz && *buf!='e'; buf += pos, bufsiz -= pos ){
125     pos = decode_dict(buf,bufsiz,(char*) 0);
126     if(!pos) break;
127     if(!decode_query(buf,pos,"ip",&ps,&i,QUERY_STR) || MAXHOSTNAMELEN < i) continue;
128     memcpy(tmphost,ps,i); tmphost[i] = '\0';
129
130     if(!decode_query(buf,pos,"port",(const char**) 0,&tmpport,QUERY_INT)) continue;
131
132     if(!decode_query(buf,pos,"peer id",&ps,&i,QUERY_STR) || i != 20 ) continue;
133
134     if(_IPsin(tmphost,tmpport,&addr) < 0){
135       fprintf(stderr,"warn, delected invalid ip address %s.\n",tmphost);
136       continue;
137     }
138
139     if( !Self.IpEquiv(addr) ){
140       cnt++;
141       IPQUEUE.Add(&addr);
142     }
143   }
144   
145   if( !cnt ) fprintf(stderr,"warn, peers list recved from tracker is empty.\n");
146   
147   return 0;
148 }
149
150 int btTracker::CheckReponse()
151 {
152 #define MAX_LINE_SIZ 32
153   char *pdata;
154   ssize_t r;
155   size_t q, hlen, dlen;
156
157   r = m_reponse_buffer.FeedIn(m_sock);
158
159   if( r > 0 ) return 0;
160   
161   q = m_reponse_buffer.Count();
162
163   Reset( (-1 == r) ? 15 : 0 );
164
165   if( !q ){
166     int error = 0;
167     socklen_t n = sizeof(error);
168     if(getsockopt(m_sock, SOL_SOCKET,SO_ERROR,&error,&n) < 0 ||
169        error != 0 ){
170       fprintf(stderr,"warn, recved nothing from tracker! %s\n",strerror(error));
171     }
172     return -1;
173   }
174
175   hlen = Http_split(m_reponse_buffer.BasePointer(), q, &pdata,&dlen);
176
177   if( !hlen ){
178     fprintf(stderr,"warn, tracker reponse invalid. no html header found.\n");
179     return -1;
180   }
181
182   r = Http_reponse_code(m_reponse_buffer.BasePointer(),hlen);
183   if ( r != 200 ){
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 )
187         return -1;
188
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);
191         return -1;
192       }
193
194       strcpy(tmppath,m_path);
195       
196       if(MAXPATHLEN < snprintf(m_path,MAXPATHLEN,REQ_URL_P1_FMT,
197                                tmppath,
198                                Http_url_encode(ih_buf, (char*)BTCONTENT.GetInfoHash(), 20),
199                                Http_url_encode(pi_buf, (char*)BTCONTENT.GetPeerId(), 20),
200                                cfg_listen_port)){
201         return -1;
202       }
203
204       return Connect();
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");
210       return -1;
211     }else
212       return 0;
213   }
214
215   if ( !pdata ) return 0;
216
217   if( !m_f_started ) m_f_started = 1;
218   m_connect_refuse_click = 0;
219
220   return _UpdatePeerList(pdata,dlen);
221 }
222
223 int btTracker::Initial()
224 {
225   char ih_buf[20 * 3 + 1],pi_buf[20 * 3 + 1],tmppath[MAXPATHLEN];
226
227   if(Http_url_analyse(BTCONTENT.GetAnnounce(),m_host,&m_port,m_path) < 0){
228     fprintf(stderr,"error, invalid tracker url format!\n");
229     return -1;
230   }
231
232   strcpy(tmppath,m_path);
233
234   if(MAXPATHLEN < snprintf((char*)m_path,MAXPATHLEN,REQ_URL_P1_FMT,
235                            tmppath,
236                            Http_url_encode(ih_buf,(char*)BTCONTENT.GetInfoHash(),20),
237                            Http_url_encode(pi_buf,(char*)BTCONTENT.GetPeerId(),20),
238                            cfg_listen_port)){
239     return -1;
240   }
241   return 0;
242 }
243
244 int btTracker::Connect()
245 {
246   ssize_t r;
247   time(&m_last_timestamp);
248
249   if(_s2sin(m_host,m_port,&m_sin) < 0) {
250     fprintf(stderr,"warn, get tracker's ip address failed.");
251     return -1;
252   }
253
254   m_sock = socket(AF_INET,SOCK_STREAM,0);
255   if(INVALID_SOCKET == m_sock) return -1;
256
257   if(setfd_nonblock(m_sock) < 0) {CLOSE_SOCKET(m_sock); return -1; }
258
259   r = connect_nonb(m_sock,(struct sockaddr*)&m_sin);
260
261   if( r == -1 ){ CLOSE_SOCKET(m_sock); return -1;}
262   else if( r == -2 ) m_status = T_CONNECTING;
263   else{
264     if( 0 == SendRequest()) m_status = T_READY;
265     else{ CLOSE_SOCKET(m_sock); return -1;}
266   }
267   return 0;
268 }
269
270 int btTracker::SendRequest()
271 {
272   char *event,*str_event[] = {"started","stopped","completed" };
273   char REQ_BUFFER[MAXPATHLEN];
274   socklen_t addrlen;
275
276   struct sockaddr_in addr;
277   addrlen = sizeof(struct sockaddr_in);
278
279   /* get local ip address */
280   if(getsockname(m_sock,(struct sockaddr*)&addr,&addrlen) < 0){ return -1;}
281
282   Self.SetIp(addr);
283
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 */
289     event = (char*) 0;
290   else
291     event = str_event[0];       /* started */
292
293   if(event){
294     if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P2_FMT,
295                              m_path,
296                              (size_t)Self.TotalUL(),
297                              (size_t)Self.TotalDL(),
298                              (size_t)BTCONTENT.GetLeftBytes(),
299                              event)){
300       return -1;
301     }
302   }else{
303     if(MAXPATHLEN < snprintf(REQ_BUFFER,MAXPATHLEN,REQ_URL_P3_FMT,
304                              m_path,
305                              (size_t)Self.TotalUL(),
306                              (size_t)Self.TotalDL(),
307                              (size_t)BTCONTENT.GetLeftBytes()
308                              )){
309       return -1;
310     }
311   }
312
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);
317   }
318   
319   strcat(REQ_BUFFER,"\r\n\r\n");
320   
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));
323     return -1;
324   }
325
326   return 0;
327 }
328
329 int btTracker::IntervalCheck(const time_t *pnow, fd_set *rfdp, fd_set *wfdp)
330 {
331   /* tracker communication */
332   if( T_FREE == m_status ){
333     if((*pnow - m_last_timestamp >= m_interval) &&
334        (cfg_min_peers > WORLD.TotalPeers())){
335     
336       if(Connect() < 0){ Reset(15); return -1; }
337     
338       if( m_status == T_CONNECTING ){
339         FD_SET(m_sock, rfdp);
340         FD_SET(m_sock, wfdp);
341       }else{
342         FD_SET(m_sock, rfdp);
343       }
344     }
345   }else{
346     if( m_status == T_CONNECTING ){
347       FD_SET(m_sock, rfdp);
348       FD_SET(m_sock, wfdp);
349     }else{
350       FD_SET(m_sock, rfdp);
351     }
352   }
353   return m_sock;
354 }
355
356 int btTracker::SocketReady(fd_set *rfdp, fd_set *wfdp, int *nfds)
357 {
358   if( T_FREE == m_status ) return 0;
359
360   if( T_CONNECTING == m_status && 
361       (FD_ISSET(m_sock, wfdp) || FD_ISSET(m_sock,wfdp)) ){
362     int error = 0;
363     socklen_t n = sizeof(error);
364     (*nfds)--;
365     FD_CLR(m_sock, wfdp); 
366     if(getsockopt(m_sock, SOL_SOCKET,SO_ERROR,&error,&n) < 0 ||
367        error != 0 ){
368       if( ECONNREFUSED != error )
369         fprintf(stderr,"warn, connect to tracker failed. %s\n",strerror(error));
370       else
371         m_connect_refuse_click++;
372       Reset(15);
373       return -1;
374     }else{
375       if( SendRequest() == 0 ) m_status = T_READY; 
376       else { Reset(15); return -1; }
377     }
378   }else if(FD_ISSET(m_sock, rfdp) ){
379     (*nfds)--;
380     FD_CLR(m_sock,rfdp);
381     CheckReponse();
382   }
383   return 0;
384 }