diff options
-rw-r--r-- | src/Network/BitTorrent/Internal.lhs | 79 |
1 files changed, 60 insertions, 19 deletions
diff --git a/src/Network/BitTorrent/Internal.lhs b/src/Network/BitTorrent/Internal.lhs index 8dbf488e..c0562223 100644 --- a/src/Network/BitTorrent/Internal.lhs +++ b/src/Network/BitTorrent/Internal.lhs | |||
@@ -317,7 +317,7 @@ fresh required extensions. | |||
317 | * The number of /swarms/ to join, each swarm described by the | 317 | * The number of /swarms/ to join, each swarm described by the |
318 | 'SwarmSession'. | 318 | 'SwarmSession'. |
319 | 319 | ||
320 | Normally, you would have one client session, however, if we need, in | 320 | Normally, you would have one client session, however, if we needed, in |
321 | one application we could have many clients with different peer ID's | 321 | one application we could have many clients with different peer ID's |
322 | and different enabled extensions at the same time. | 322 | and different enabled extensions at the same time. |
323 | 323 | ||
@@ -461,28 +461,60 @@ However if client is a seeder then the value depends on . | |||
461 | > data SwarmSession = SwarmSession { | 461 | > data SwarmSession = SwarmSession { |
462 | > torrentMeta :: !Torrent | 462 | > torrentMeta :: !Torrent |
463 | 463 | ||
464 | > -- | | ||
465 | > , clientSession :: !ClientSession | 464 | > , clientSession :: !ClientSession |
466 | 465 | ||
467 | > -- | Represent count of peers we _currently_ can connect to in the | 466 | TODO: lower "vacantPeers" when client becomes seeder according to |
468 | > -- swarm. Used to bound number of concurrent threads. | 467 | throttling policy. |
468 | |||
469 | Represent count of peers we _currently_ can connect to in the | ||
470 | swarm. Used to bound number of concurrent threads. See also *Thread | ||
471 | Throttling* section. | ||
472 | |||
469 | > , vacantPeers :: !(MSem SessionCount) | 473 | > , vacantPeers :: !(MSem SessionCount) |
470 | 474 | ||
471 | > -- | Modify this carefully updating global progress. | 475 | Client bitfield is used to keep track "the client have" piece set. |
476 | Modify this carefully always updating global progress. | ||
477 | |||
472 | > , clientBitfield :: !(TVar Bitfield) | 478 | > , clientBitfield :: !(TVar Bitfield) |
473 | 479 | ||
480 | We keep set of the all connected peers for the each particular torrent | ||
481 | to prevent duplicated and therefore reduntant TCP connections. For | ||
482 | example consider the following very simle and realistic scenario: | ||
483 | |||
484 | * Peer A lookup tracker for peers. | ||
485 | |||
486 | * Peer B lookup tracker for peers. | ||
487 | |||
488 | * Finally, Peer A connect to B and Peer B connect to peer A | ||
489 | simultaneously. | ||
490 | |||
491 | There some other situation the problem may occur: duplicates in | ||
492 | successive tracker responses, tracker and DHT returns. | ||
493 | |||
494 | So without any protection we end up with two session between the same | ||
495 | peers. That's bad because this could lead: | ||
496 | |||
497 | * Reduced throughput - multiple sessions between the same peers will | ||
498 | mutiply control overhead (control messages, session state). | ||
499 | |||
500 | * Thread occupation - duplicated sessions will eat thread slots and | ||
501 | discourage other, possible more useful, peers to establish connection. | ||
502 | |||
503 | To avoid this we could check, into the one transaction, if a peer is | ||
504 | already connected and add a connection only if it is not. | ||
505 | |||
474 | > , connectedPeers :: !(TVar (Set PeerSession)) | 506 | > , connectedPeers :: !(TVar (Set PeerSession)) |
475 | 507 | ||
476 | > -- TODO use bounded broadcast chan with priority queue and drop old entries | 508 | TODO: use bounded broadcast chan with priority queue and drop old entries. |
477 | > -- | Channel used for replicate messages across all peers in | 509 | |
478 | > -- swarm. For exsample if we get some piece we should sent to all | 510 | Channel used for replicate messages across all peers in swarm. For |
479 | > -- connected (and interested in) peers HAVE message. | 511 | exsample if we get some piece we should sent to all connected (and |
480 | > -- | 512 | interested in) peers HAVE message. |
513 | |||
481 | > , broadcastMessages :: !(TChan Message) | 514 | > , broadcastMessages :: !(TChan Message) |
482 | > } | 515 | > } |
483 | 516 | ||
484 | > -- INVARIANT: | 517 | INVARIANT: max_sessions_count - sizeof connectedPeers = value vacantPeers |
485 | > -- max_sessions_count - sizeof connectedPeers = value vacantPeers | ||
486 | 518 | ||
487 | > instance Eq SwarmSession where | 519 | > instance Eq SwarmSession where |
488 | > (==) = (==) `on` (tInfoHash . torrentMeta) | 520 | > (==) = (==) `on` (tInfoHash . torrentMeta) |
@@ -523,6 +555,10 @@ However if client is a seeder then the value depends on . | |||
523 | > getClientBitfield :: SwarmSession -> IO Bitfield | 555 | > getClientBitfield :: SwarmSession -> IO Bitfield |
524 | > getClientBitfield = readTVarIO . clientBitfield | 556 | > getClientBitfield = readTVarIO . clientBitfield |
525 | 557 | ||
558 | > pieceLength :: SwarmSession -> Int | ||
559 | > pieceLength = ciPieceLength . tInfo . torrentMeta | ||
560 | > {-# INLINE pieceLength #-} | ||
561 | |||
526 | > {- | 562 | > {- |
527 | > haveDone :: MonadIO m => PieceIx -> SwarmSession -> m () | 563 | > haveDone :: MonadIO m => PieceIx -> SwarmSession -> m () |
528 | > haveDone ix = | 564 | > haveDone ix = |
@@ -532,7 +568,8 @@ However if client is a seeder then the value depends on . | |||
532 | > currentProgress | 568 | > currentProgress |
533 | > -} | 569 | > -} |
534 | 570 | ||
535 | > -- acquire/release mechanism: for internal use only | 571 | Peer sessions throttling |
572 | ------------------------------------------------------------------------ | ||
536 | 573 | ||
537 | > enterSwarm :: SwarmSession -> IO () | 574 | > enterSwarm :: SwarmSession -> IO () |
538 | > enterSwarm SwarmSession {..} = do | 575 | > enterSwarm SwarmSession {..} = do |
@@ -549,10 +586,6 @@ However if client is a seeder then the value depends on . | |||
549 | > bracket (enterSwarm se) (const (leaveSwarm se)) | 586 | > bracket (enterSwarm se) (const (leaveSwarm se)) |
550 | > . const | 587 | > . const |
551 | 588 | ||
552 | > pieceLength :: SwarmSession -> Int | ||
553 | > pieceLength = ciPieceLength . tInfo . torrentMeta | ||
554 | > {-# INLINE pieceLength #-} | ||
555 | |||
556 | Peer sessions | 589 | Peer sessions |
557 | ------------------------------------------------------------------------ | 590 | ------------------------------------------------------------------------ |
558 | 591 | ||
@@ -611,6 +644,12 @@ avoid reduntant KA messages. | |||
611 | > instance Ord PeerSession where | 644 | > instance Ord PeerSession where |
612 | > compare = comparing connectedPeerAddr | 645 | > compare = comparing connectedPeerAddr |
613 | 646 | ||
647 | > findPieceCount :: PeerSession -> PieceCount | ||
648 | > findPieceCount = pieceCount . tInfo . torrentMeta . swarmSession | ||
649 | |||
650 | Peer session exceptions | ||
651 | ------------------------------------------------------------------------ | ||
652 | |||
614 | > -- | Exceptions used to interrupt the current P2P session. This | 653 | > -- | Exceptions used to interrupt the current P2P session. This |
615 | > -- exceptions will NOT affect other P2P sessions, DHT, peer <-> | 654 | > -- exceptions will NOT affect other P2P sessions, DHT, peer <-> |
616 | > -- tracker, or any other session. | 655 | > -- tracker, or any other session. |
@@ -631,6 +670,9 @@ avoid reduntant KA messages. | |||
631 | > putSessionException :: SessionException -> IO () | 670 | > putSessionException :: SessionException -> IO () |
632 | > putSessionException = print | 671 | > putSessionException = print |
633 | 672 | ||
673 | Peer session creation | ||
674 | ------------------------------------------------------------------------ | ||
675 | |||
634 | > -- TODO modify such that we can use this in listener loop | 676 | > -- TODO modify such that we can use this in listener loop |
635 | > -- TODO check if it connected yet peer | 677 | > -- TODO check if it connected yet peer |
636 | > withPeerSession :: SwarmSession -> PeerAddr | 678 | > withPeerSession :: SwarmSession -> PeerAddr |
@@ -672,8 +714,7 @@ avoid reduntant KA messages. | |||
672 | > atomically $ modifyTVar' connectedPeers (S.delete ps) | 714 | > atomically $ modifyTVar' connectedPeers (S.delete ps) |
673 | > close sock | 715 | > close sock |
674 | 716 | ||
675 | > findPieceCount :: PeerSession -> PieceCount | 717 | TODO: initiatePeerSession, acceptPeerSession |
676 | > findPieceCount = pieceCount . tInfo . torrentMeta . swarmSession | ||
677 | 718 | ||
678 | Broadcasting: Have, Cancel, Bitfield, SuggestPiece | 719 | Broadcasting: Have, Cancel, Bitfield, SuggestPiece |
679 | ------------------------------------------------------------------------ | 720 | ------------------------------------------------------------------------ |