1 #include "btrequest.h"  // def.h
2 
3 #include <stdlib.h>
4 
5 #include "btcontent.h"
6 #include "btconfig.h"
7 #include "console.h"
8 
9 #ifndef HAVE_RANDOM
10 #include "compat.h"
11 #endif
12 
13 
_empty_slice_list(PSLICE * ps_head)14 static void _empty_slice_list(PSLICE *ps_head)
15 {
16   PSLICE p;
17   for(; *ps_head;){
18     p = (*ps_head)->next;
19     delete (*ps_head);
20     *ps_head = p;
21   }
22 }
23 
~RequestQueue()24 RequestQueue::~RequestQueue()
25 {
26   if( rq_head ) _empty_slice_list(&rq_head);
27 }
28 
RequestQueue()29 RequestQueue::RequestQueue()
30 {
31   rq_head = (PSLICE) 0;
32   rq_send = rq_head;
33 }
34 
Empty()35 void RequestQueue::Empty()
36 {
37   if(rq_head) _empty_slice_list(&rq_head);
38   rq_send = rq_head;
39 }
40 
SetHead(PSLICE ps)41 void RequestQueue::SetHead(PSLICE ps)
42 {
43   if( rq_head ) _empty_slice_list(&rq_head);
44   rq_head = ps;
45   rq_send = rq_head;
46 }
47 
operator =(RequestQueue & rq)48 void RequestQueue::operator=(RequestQueue &rq)
49 {
50   PSLICE n, u = (PSLICE) 0;
51   size_t idx;
52   int flag = 0;
53 
54   if( rq_head ) _empty_slice_list(&rq_head);
55   rq_head = rq.rq_head;
56   rq_send = rq_head;
57 
58   // Reassign only the first piece represented in the queue.
59   n = rq_head;
60   idx = n->index;
61   for( ; n ; u = n,n = u->next ){
62     if( rq.rq_send == n ) flag = 1;
63     if( n->index != idx ) break;
64   }
65   if(n){
66     u->next = (PSLICE) 0;
67     rq.rq_head = n;
68     if(flag) rq.rq_send = rq.rq_head;
69   }else{
70     rq.rq_head = (PSLICE) 0;
71     rq.rq_send = rq.rq_head;
72   }
73 }
74 
Copy(const RequestQueue * prq,size_t idx)75 int RequestQueue::Copy(const RequestQueue *prq, size_t idx)
76 {
77   PSLICE n, u, ps;
78   int found = 0;
79 
80   if( prq->IsEmpty() ) return 0;
81 
82   n = rq_head;
83   u = (PSLICE)0;
84   for( ; n ; u = n, n = u->next );  // move to end
85 
86   ps = prq->GetHead();
87   for( ; ps; ps = ps->next ){
88     if( ps->index != idx ){
89       if( found ) break;
90       else continue;
91     }else found = 1;
92     if( Add(ps->index, ps->offset, ps->length) < 0 ){
93       PSLICE temp;
94       for( n = u ? u->next : rq_head; n; n=temp ){
95         temp = n->next;
96         delete n;
97       }
98       if( u ) u->next = (PSLICE)0;
99       return -1;
100     }
101   }
102   return 0;
103 }
104 
CopyShuffle(const RequestQueue * prq,size_t idx)105 int RequestQueue::CopyShuffle(const RequestQueue *prq, size_t idx)
106 {
107   PSLICE n, u, ps, prev, end, psnext, temp;
108   SLICE dummy;
109   unsigned long rndbits;
110   int len, shuffle, i=0, setsend=0;
111   size_t firstoff;
112 
113   if( prq->IsEmpty() ) return 0;
114 
115   n = rq_head;
116   u = (PSLICE)0;
117   for( ; n ; u = n, n = u->next );  // move to end
118 
119   if( !rq_send ) setsend = 1;
120 
121   ps = prq->GetHead();
122   for( ; ps && ps->index != idx; ps = ps->next );
123   if( !ps ) return -1;
124   firstoff = ps->offset;
125   for( len=0; ps && ps->index == idx; ps = ps->next ){
126     if( Add(ps->index, ps->offset, ps->length) < 0 ){
127       for( n = u ? u->next : rq_head; n; n=temp ){
128         temp = n->next;
129         delete n;
130       }
131       if( u ) u->next = (PSLICE)0;
132       return -1;
133     }
134     len++;
135   }
136   if( !u ){
137     u = &dummy;
138     u->next = rq_head;
139   }
140 
141   shuffle = (random()&0x07)+2;
142   if( shuffle > len/2 ) shuffle = len/2;
143   for( ; shuffle; shuffle-- ){
144     prev = u;
145     ps = u->next->next;
146     u->next->next = (PSLICE)0;
147     end = u->next;
148     for( ; ps; ps = psnext ){
149       psnext = ps->next;
150       if( !i-- ){
151         rndbits = random();
152         i = sizeof(rndbits) - 3;  // insure an extra bit
153       }
154       if( (rndbits>>=1)&01 ){  // beginning or end of list
155         if( (rndbits>>=1)&01 ){
156           prev = end;
157           ps->next = (PSLICE)0;
158           end->next = ps;
159           end = ps;
160         }else{
161           ps->next = u->next;
162           u->next = ps;
163           prev = u;
164         }
165       }else{  // before or after previous insertion
166         if( (rndbits>>=1)&01 ){  // put after prev->next
167           if( end == prev->next ) end = ps;
168           temp = prev->next;
169           ps->next = prev->next->next;
170           prev->next->next = ps;
171           prev = temp;
172         }else{  // put after prev (before prev->next)
173           ps->next = prev->next;
174           prev->next = ps;
175         }
176       }
177     }
178   }  // shuffle loop
179 
180   // If first slice is the same as in the original, move it to the end.
181   if( u->next->offset == firstoff ){
182     end->next = u->next;
183     u->next = u->next->next;
184     end = end->next;
185     end->next = (PSLICE)0;
186   }
187   if( u == &dummy ) rq_head = u->next;
188   if( setsend ) rq_send = u->next;
189 
190   return 0;
191 }
192 
193 // Counts all queued slices.
Qsize() const194 size_t RequestQueue::Qsize() const
195 {
196   size_t cnt = 0;
197   PSLICE n = rq_head;
198   PSLICE u = (PSLICE) 0;
199 
200   for( ; n ; u = n,n = u->next ) cnt++; // move to end
201   return cnt;
202 }
203 
204 // Counts only slices from one piece.
Qlen(size_t piece) const205 size_t RequestQueue::Qlen(size_t piece) const
206 {
207   size_t cnt = 0;
208   PSLICE n = rq_head;
209   PSLICE u = (PSLICE) 0;
210   size_t idx;
211 
212   for( ; n && n->index != piece; n = n->next );
213 
214   if(n) idx = n->index;
215   for( ; n ; u = n,n = u->next ){
216     if( n->index != idx ) break;
217     cnt++;
218   }
219   return cnt;
220 }
221 
LastSlice() const222 int RequestQueue::LastSlice() const
223 {
224   return ( rq_head &&
225           (!rq_head->next || rq_head->index != rq_head->next->index) ) ? 1 : 0;
226 }
227 
Insert(PSLICE ps,size_t idx,size_t off,size_t len)228 int RequestQueue::Insert(PSLICE ps,size_t idx,size_t off,size_t len)
229 {
230   PSLICE n;
231 
232   n = new SLICE;
233 
234 #ifndef WINDOWS
235   if( !n ) return -1;
236 #endif
237 
238   n->index = idx;
239   n->offset = off;
240   n->length = len;
241   n->reqtime = (time_t) 0;
242 
243   // ps is the slice to insert after; if 0, insert at the head.
244   if(ps){
245     n->next = ps->next;
246     ps->next = n;
247     if( rq_send == n->next ) rq_send = n;
248   }else{
249     n->next = rq_head;
250     rq_head = n;
251     rq_send = rq_head;
252   }
253 
254   return 0;
255 }
256 
Add(size_t idx,size_t off,size_t len)257 int RequestQueue::Add(size_t idx,size_t off,size_t len)
258 {
259   PSLICE n = rq_head;
260   PSLICE u = (PSLICE) 0;
261 
262   for( ; n ; u = n,n = u->next ); // move to end
263 
264   n = new SLICE;
265 
266 #ifndef WINDOWS
267   if( !n ) return -1;
268 #endif
269 
270   n->next = (PSLICE) 0;
271   n->index = idx;
272   n->offset = off;
273   n->length = len;
274   n->reqtime = (time_t) 0;
275 
276   if( u ) u->next = n;
277   else{
278     rq_head = n;
279     rq_send = rq_head;
280   }
281 
282   if( !rq_send ) rq_send = n;
283 
284   return 0;
285 }
286 
Append(PSLICE ps)287 int RequestQueue::Append(PSLICE ps)
288 {
289   PSLICE n = rq_head;
290   PSLICE u = (PSLICE) 0;
291 
292   for( ; n ; u = n,n = u->next ); // move to end
293 
294   if(u) u->next = ps;
295   else rq_head = ps;
296 
297   if( !rq_send ) rq_send = ps;
298 
299   return 0;
300 }
301 
Remove(size_t idx,size_t off,size_t len)302 int RequestQueue::Remove(size_t idx,size_t off,size_t len)
303 {
304   PSLICE n = rq_head;
305   PSLICE u = (PSLICE) 0;
306 
307   for( ; n ; u = n, n = u->next ){
308     if( n->index == idx && n->offset == off && n->length == len ) break;
309   }
310 
311   if( !n ) return -1;	/* not found */
312 
313   if( u ) u->next = n->next; else rq_head = n->next;
314   if( rq_send == n ) rq_send = n->next;
315   delete n;
316 
317   return 0;
318 }
319 
320 // Add a slice at an appropriate place in the queue.
321 // returns -1 if failed, 1 if request needs to be sent.
Requeue(size_t idx,size_t off,size_t len)322 int RequestQueue::Requeue(size_t idx,size_t off,size_t len)
323 {
324   int f_send, retval;
325   PSLICE n = rq_head;
326   PSLICE u = (PSLICE) 0;
327   PSLICE save_send = rq_send;
328 
329   // find last slice of same piece
330   if( rq_send ) f_send = 1;
331   for( ; n ; u = n,n = u->next ){
332     if( rq_send == u ) f_send = 0;
333     if( u && idx == u->index && idx != n->index ) break;
334   }
335   if( !u ) f_send = 1;
336 
337   retval = ( Insert(u,idx,off,len) < 0 ) ? -1 : f_send;
338   rq_send = save_send;
339   return retval;
340 }
341 
342 // Move the slice to the end of its piece sequence.
MoveLast(PSLICE ps)343 void RequestQueue::MoveLast(PSLICE ps)
344 {
345   PSLICE n, u;
346 
347   for( n = rq_head; n && n->next != ps; n = n->next );
348   if( !n || !ps ) return;
349   for( u = ps; u->next && u->next->index == ps->index; u = u->next );
350   if( u == ps ) return;
351 
352   if( rq_send == ps ) rq_send = ps->next;
353   else if( rq_send == u->next ) rq_send = ps;
354   n->next = ps->next;
355   ps->next = u->next;
356   u->next = ps;
357 }
358 
HasIdx(size_t idx) const359 int RequestQueue::HasIdx(size_t idx) const
360 {
361   PSLICE n = rq_head;
362 
363   for( ; n ; n = n->next ){
364     if(n->index == idx) break;
365   }
366 
367   return n ? 1 : 0;
368 }
369 
HasSlice(size_t idx,size_t off,size_t len) const370 int RequestQueue::HasSlice(size_t idx, size_t off, size_t len) const
371 {
372   PSLICE n = rq_head;
373 
374   for( ; n ; n = n->next ){
375     if( n->index == idx && n->offset == off && n->length == len ) break;
376   }
377 
378   return n ? 1 : 0;
379 }
380 
GetReqTime(size_t idx,size_t off,size_t len) const381 time_t RequestQueue::GetReqTime(size_t idx,size_t off,size_t len) const
382 {
383   PSLICE n = rq_head;
384 
385   for( ; n ; n = n->next ){
386     if( n->index == idx && n->offset == off && n->length == len ) break;
387   }
388 
389   if( !n ) return (time_t)0;	/* not found */
390 
391   return n->reqtime;
392 }
393 
SetReqTime(PSLICE n,time_t t)394 void RequestQueue::SetReqTime(PSLICE n,time_t t)
395 {
396   n->reqtime = t;
397 }
398 
Pop(size_t * pidx,size_t * poff,size_t * plen)399 int RequestQueue::Pop(size_t *pidx,size_t *poff,size_t *plen)
400 {
401   PSLICE n;
402 
403   if( !rq_head ) return -1;
404 
405   n = rq_head->next;
406 
407   if(pidx) *pidx = rq_head->index;
408   if(poff) *poff = rq_head->offset;
409   if(plen) *plen = rq_head->length;
410 
411   if( rq_send == rq_head ) rq_send = n;
412   delete rq_head;
413 
414   rq_head = n;
415 
416   return 0;
417 }
418 
Peek(size_t * pidx,size_t * poff,size_t * plen) const419 int RequestQueue::Peek(size_t *pidx,size_t *poff,size_t *plen) const
420 {
421   if( !rq_head ) return -1;
422 
423   if(pidx) *pidx = rq_head->index;
424   if(poff) *poff = rq_head->offset;
425   if(plen) *plen = rq_head->length;
426 
427   return 0;
428 }
429 
CreateWithIdx(size_t idx)430 int RequestQueue::CreateWithIdx(size_t idx)
431 {
432   size_t i,off,len,ns;
433 
434   ns = NSlices(idx);
435 
436   for( i = off = 0; i < ns; i++ ){
437     len = Slice_Length(idx,i);
438     if( Add(idx,off,len) < 0 ) return -1;
439     off += len;
440   }
441 
442   return 0;
443 }
444 
Slice_Length(size_t idx,size_t sidx) const445 size_t RequestQueue::Slice_Length(size_t idx,size_t sidx) const
446 {
447   size_t plen = BTCONTENT.GetPieceLength(idx);
448 
449   return (sidx == ( plen / cfg_req_slice_size)) ?
450     (plen % cfg_req_slice_size) :
451     cfg_req_slice_size;
452 }
453 
NSlices(size_t idx) const454 size_t RequestQueue::NSlices(size_t idx) const
455 {
456   size_t r,n;
457   r = BTCONTENT.GetPieceLength(idx);
458   n = r / cfg_req_slice_size;
459   return ( r % cfg_req_slice_size ) ? n + 1 : n;
460 }
461 
IsValidRequest(size_t idx,size_t off,size_t len) const462 int RequestQueue::IsValidRequest(size_t idx,size_t off,size_t len) const
463 {
464   return ( idx < BTCONTENT.GetNPieces() &&
465            len &&
466            (off + len) <= BTCONTENT.GetPieceLength(idx) &&
467            len <= cfg_max_slice_size ) ?
468     1 : 0;
469 }
470 
471 // ****************************** PendingQueue ******************************
472 
473 PendingQueue PENDINGQUEUE;
474 
PendingQueue()475 PendingQueue::PendingQueue()
476 {
477   int i = 0;
478   for(; i < PENDING_QUEUE_SIZE; i++) pending_array[i] = (PSLICE) 0;
479   pq_count = 0;
480 }
481 
~PendingQueue()482 PendingQueue::~PendingQueue()
483 {
484   if(pq_count) Empty();
485 }
486 
Empty()487 void PendingQueue::Empty()
488 {
489   int i = 0;
490   for ( ; i < PENDING_QUEUE_SIZE && pq_count; i++ )
491     if( pending_array[i] != (PSLICE) 0 ){
492       _empty_slice_list(&(pending_array[i]));
493       pq_count--;
494     }
495 }
496 
Exist(size_t idx) const497 int PendingQueue::Exist(size_t idx) const
498 {
499   int i, j = 0;
500   for ( i = 0; i < PENDING_QUEUE_SIZE && j < pq_count; i++ ){
501     if( pending_array[i] ){
502       j++;
503       if( idx == pending_array[i]->index ) return 1;
504     }
505   }
506   return 0;
507 }
508 
HasSlice(size_t idx,size_t off,size_t len)509 int PendingQueue::HasSlice(size_t idx, size_t off, size_t len)
510 {
511   int i, j = 0;
512   for( i = 0; i < PENDING_QUEUE_SIZE && j < pq_count; i++ ){
513     if( pending_array[i] ){
514       j++;
515       if( idx == pending_array[i]->index &&
516           off == pending_array[i]->offset && len == pending_array[i]->length )
517         return 1;
518     }
519   }
520   return 0;
521 }
522 
523 /* Sending an empty queue to this function WILL cause a crash.  This exposure
524    is left open in order to help track down bugs that cause this condition.
525    Returns:
526       0 if all pieces were added to Pending
527      -1 if Pending is full (at least one piece not added)
528       1 if at least one piece was already in Pending
529 */
Pending(RequestQueue * prq)530 int PendingQueue::Pending(RequestQueue *prq)
531 {
532   int retval = 0;
533   int i = 0, j = -1;
534   PSLICE n, u = (PSLICE) 0;
535   size_t idx, off, len;
536   RequestQueue tmprq;
537 
538   if( pq_count >= PENDING_QUEUE_SIZE ){
539     prq->Empty();
540     return -1;
541   }
542   if( prq->Qlen(prq->GetRequestIdx()) >=
543       BTCONTENT.GetPieceLength() / cfg_req_slice_size ){
544     // This shortcut relies on the fact that we don't add to a queue if it
545     // already contains a full piece.
546     prq->Empty();
547     return 0;
548   }
549 
550   for( ; i < PENDING_QUEUE_SIZE; i++ ){
551     if( pending_array[i] == (PSLICE)0 ){
552       // Find an empty slot in case we need it.
553       if(j<0) j = i;
554     }else if( prq->GetRequestIdx() == pending_array[i]->index ){
555       // Don't add a piece to Pending more than once.
556       while( !prq->IsEmpty() &&
557           prq->GetRequestIdx() == pending_array[i]->index )
558         prq->Pop(&idx,&off,&len);
559       retval = 1;
560       if( prq->IsEmpty() ) return retval;
561       i = 0;
562     }
563   }
564   pending_array[j] = prq->GetHead();
565   prq->Release();
566   pq_count++;
567 
568   // If multiple pieces are queued, break up the queue separately.
569   n = pending_array[j];
570   idx = n->index;
571   for( ; n ; u = n, n = u->next ){
572     if( n->index != idx ) break;
573     n->reqtime = (time_t)0;
574   }
575   if(n){
576     u->next = (PSLICE) 0;
577     tmprq.SetHead(n);
578     i = Pending(&tmprq);
579     if( i < 0 ) retval = i;
580     else if( i > 0 && retval == 0 ) retval = i;
581     tmprq.Release();
582   }
583 
584   return retval;
585 }
586 
ReAssign(RequestQueue * prq,BitField & bf)587 size_t PendingQueue::ReAssign(RequestQueue *prq, BitField &bf)
588 {
589   int i = 0;
590   size_t sc = pq_count;
591   size_t idx = BTCONTENT.GetNPieces();
592 
593   for( ; i < PENDING_QUEUE_SIZE && sc; i++ ){
594     if( pending_array[i] != (PSLICE) 0){
595       if( bf.IsSet(pending_array[i]->index) &&
596           !prq->HasIdx(pending_array[i]->index) ){
597         idx = pending_array[i]->index;
598         prq->Append(pending_array[i]);
599         pending_array[i] = (PSLICE) 0;
600         pq_count--;
601         Delete(idx); // delete any copies from Pending
602         break;
603       }
604       sc--;
605     }
606   }
607   // Return value now indicates the assigned piece or GetNPieces
608   return idx;
609 }
610 
Delete(size_t idx)611 int PendingQueue::Delete(size_t idx)
612 {
613   int i, j = 0, r = 0;
614   for ( i = 0; i < PENDING_QUEUE_SIZE && j < pq_count; i++ ){
615     if( pending_array[i] ){
616       j++;
617       if( idx == pending_array[i]->index ){
618         r = 1;
619         _empty_slice_list(&(pending_array[i]));
620         pq_count--;
621         break;
622       }
623     }
624   }
625   return r;
626 }
627 
DeleteSlice(size_t idx,size_t off,size_t len)628 int PendingQueue::DeleteSlice(size_t idx, size_t off, size_t len)
629 {
630   int i, j = 0, r = 0;
631   RequestQueue rq;
632   for( i = 0; i < PENDING_QUEUE_SIZE && j < pq_count; i++ ){
633     if( pending_array[i] ){
634       j++;
635       if( idx == pending_array[i]->index ){
636         //check if off & len match any slice
637         //remove the slice if so
638         rq.SetHead(pending_array[i]);
639         if( rq.Remove(idx, off, len) == 0 ){
640           r = 1;
641           pending_array[i] = rq.GetHead();
642           if( (PSLICE) 0 == pending_array[i] ) pq_count--;
643           i = PENDING_QUEUE_SIZE;   // exit loop
644         }
645         rq.Release();
646       }
647     }
648   }
649   return r;
650 }
651 
652