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