diff options
-rw-r--r-- | bittorrent.cabal | 1 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange/Connection.hs | 111 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange/Connection/Status.hs | 131 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange/Session.hs | 1 |
4 files changed, 105 insertions, 139 deletions
diff --git a/bittorrent.cabal b/bittorrent.cabal index 91d227b2..af6caefa 100644 --- a/bittorrent.cabal +++ b/bittorrent.cabal | |||
@@ -72,7 +72,6 @@ library | |||
72 | Network.BitTorrent.Exchange.Assembler | 72 | Network.BitTorrent.Exchange.Assembler |
73 | Network.BitTorrent.Exchange.Block | 73 | Network.BitTorrent.Exchange.Block |
74 | Network.BitTorrent.Exchange.Connection | 74 | Network.BitTorrent.Exchange.Connection |
75 | Network.BitTorrent.Exchange.Connection.Status | ||
76 | Network.BitTorrent.Exchange.Manager | 75 | Network.BitTorrent.Exchange.Manager |
77 | Network.BitTorrent.Exchange.Message | 76 | Network.BitTorrent.Exchange.Message |
78 | Network.BitTorrent.Exchange.Selection | 77 | Network.BitTorrent.Exchange.Selection |
diff --git a/src/Network/BitTorrent/Exchange/Connection.hs b/src/Network/BitTorrent/Exchange/Connection.hs index dde9a468..fd9022da 100644 --- a/src/Network/BitTorrent/Exchange/Connection.hs +++ b/src/Network/BitTorrent/Exchange/Connection.hs | |||
@@ -49,6 +49,19 @@ module Network.BitTorrent.Exchange.Connection | |||
49 | , connSession | 49 | , connSession |
50 | , connStats | 50 | , connStats |
51 | 51 | ||
52 | -- ** Status | ||
53 | , PeerStatus (..) | ||
54 | , ConnectionStatus (..) | ||
55 | , updateStatus | ||
56 | , statusUpdates | ||
57 | , clientStatus | ||
58 | , remoteStatus | ||
59 | , canUpload | ||
60 | , canDownload | ||
61 | , defaultUnchokeSlots | ||
62 | , defaultRechokeInterval | ||
63 | |||
64 | |||
52 | -- * Setup | 65 | -- * Setup |
53 | , ConnectionPrefs (..) | 66 | , ConnectionPrefs (..) |
54 | , SessionLink (..) | 67 | , SessionLink (..) |
@@ -102,21 +115,21 @@ import Control.Monad.State | |||
102 | import Control.Lens | 115 | import Control.Lens |
103 | import Data.ByteString as BS | 116 | import Data.ByteString as BS |
104 | import Data.ByteString.Lazy as BSL | 117 | import Data.ByteString.Lazy as BSL |
105 | import Data.Conduit | 118 | import Data.Conduit as C |
106 | import Data.Conduit.Cereal | 119 | import Data.Conduit.Cereal |
107 | import Data.Conduit.List | 120 | import Data.Conduit.List |
108 | import Data.Conduit.Network | 121 | import Data.Conduit.Network |
109 | import Data.Default | 122 | import Data.Default |
110 | import Data.IORef | 123 | import Data.IORef |
111 | import Data.List as L | 124 | import Data.List as L |
112 | import Data.Maybe | 125 | import Data.Maybe as M |
113 | import Data.Monoid | 126 | import Data.Monoid |
114 | import Data.Serialize as S | 127 | import Data.Serialize as S |
115 | import Data.Typeable | 128 | import Data.Typeable |
116 | import Network | 129 | import Network |
117 | import Network.Socket hiding (Connected) | 130 | import Network.Socket hiding (Connected) |
118 | import Network.Socket.ByteString as BS | 131 | import Network.Socket.ByteString as BS |
119 | import Text.PrettyPrint as PP hiding (($$), (<>)) | 132 | import Text.PrettyPrint as PP hiding ((<>)) |
120 | import Text.PrettyPrint.Class | 133 | import Text.PrettyPrint.Class |
121 | import Text.Show.Functions () | 134 | import Text.Show.Functions () |
122 | import System.Log.FastLogger (ToLogStr(..)) | 135 | import System.Log.FastLogger (ToLogStr(..)) |
@@ -125,7 +138,6 @@ import System.Timeout | |||
125 | import Data.Torrent.Bitfield as BF | 138 | import Data.Torrent.Bitfield as BF |
126 | import Data.Torrent.InfoHash | 139 | import Data.Torrent.InfoHash |
127 | import Network.BitTorrent.Core | 140 | import Network.BitTorrent.Core |
128 | import Network.BitTorrent.Exchange.Connection.Status | ||
129 | import Network.BitTorrent.Exchange.Message as Msg | 141 | import Network.BitTorrent.Exchange.Message as Msg |
130 | 142 | ||
131 | -- TODO handle port message? | 143 | -- TODO handle port message? |
@@ -463,6 +475,93 @@ instance Default Options where | |||
463 | } | 475 | } |
464 | 476 | ||
465 | {----------------------------------------------------------------------- | 477 | {----------------------------------------------------------------------- |
478 | -- Peer status | ||
479 | -----------------------------------------------------------------------} | ||
480 | |||
481 | -- | Connections contain two bits of state on either end: choked or | ||
482 | -- not, and interested or not. | ||
483 | data PeerStatus = PeerStatus | ||
484 | { -- | Choking is a notification that no data will be sent until | ||
485 | -- unchoking happens. | ||
486 | _choking :: !Bool | ||
487 | |||
488 | -- | | ||
489 | , _interested :: !Bool | ||
490 | } deriving (Show, Eq, Ord) | ||
491 | |||
492 | $(makeLenses ''PeerStatus) | ||
493 | |||
494 | instance Pretty PeerStatus where | ||
495 | pretty PeerStatus {..} = | ||
496 | pretty (Choking _choking) <+> "and" <+> pretty (Interested _interested) | ||
497 | |||
498 | -- | Connections start out choked and not interested. | ||
499 | instance Default PeerStatus where | ||
500 | def = PeerStatus True False | ||
501 | |||
502 | instance Monoid PeerStatus where | ||
503 | mempty = def | ||
504 | mappend a b = PeerStatus | ||
505 | { _choking = _choking a && _choking b | ||
506 | , _interested = _interested a || _interested b | ||
507 | } | ||
508 | |||
509 | -- | Can be used to update remote peer status using incoming 'Status' | ||
510 | -- message. | ||
511 | updateStatus :: StatusUpdate -> PeerStatus -> PeerStatus | ||
512 | updateStatus (Choking b) = choking .~ b | ||
513 | updateStatus (Interested b) = interested .~ b | ||
514 | |||
515 | -- | Can be used to generate outcoming messages. | ||
516 | statusUpdates :: PeerStatus -> PeerStatus -> [StatusUpdate] | ||
517 | statusUpdates a b = M.catMaybes $ | ||
518 | [ if _choking a == _choking b then Nothing | ||
519 | else Just $ Choking $ _choking b | ||
520 | , if _interested a == _interested b then Nothing | ||
521 | else Just $ Interested $ _interested b | ||
522 | ] | ||
523 | |||
524 | {----------------------------------------------------------------------- | ||
525 | -- Connection status | ||
526 | -----------------------------------------------------------------------} | ||
527 | |||
528 | -- | Status of the both endpoints. | ||
529 | data ConnectionStatus = ConnectionStatus | ||
530 | { _clientStatus :: !PeerStatus | ||
531 | , _remoteStatus :: !PeerStatus | ||
532 | } deriving (Show, Eq) | ||
533 | |||
534 | $(makeLenses ''ConnectionStatus) | ||
535 | |||
536 | instance Pretty ConnectionStatus where | ||
537 | pretty ConnectionStatus {..} = | ||
538 | "this " PP.<+> pretty _clientStatus PP.$$ | ||
539 | "remote" PP.<+> pretty _remoteStatus | ||
540 | |||
541 | -- | Connections start out choked and not interested. | ||
542 | instance Default ConnectionStatus where | ||
543 | def = ConnectionStatus def def | ||
544 | |||
545 | -- | Can the client transfer to the remote peer? | ||
546 | canUpload :: ConnectionStatus -> Bool | ||
547 | canUpload ConnectionStatus {..} | ||
548 | = _interested _remoteStatus && not (_choking _clientStatus) | ||
549 | |||
550 | -- | Can the client transfer from the remote peer? | ||
551 | canDownload :: ConnectionStatus -> Bool | ||
552 | canDownload ConnectionStatus {..} | ||
553 | = _interested _clientStatus && not (_choking _remoteStatus) | ||
554 | |||
555 | -- | Indicates how many peers are allowed to download from the client | ||
556 | -- by default. | ||
557 | defaultUnchokeSlots :: Int | ||
558 | defaultUnchokeSlots = 4 | ||
559 | |||
560 | -- | | ||
561 | defaultRechokeInterval :: Int | ||
562 | defaultRechokeInterval = 10 * 1000 * 1000 | ||
563 | |||
564 | {----------------------------------------------------------------------- | ||
466 | -- Connection | 565 | -- Connection |
467 | -----------------------------------------------------------------------} | 566 | -----------------------------------------------------------------------} |
468 | 567 | ||
@@ -681,7 +780,7 @@ runWire action sock chan conn = flip runReaderT conn $ runConnected $ | |||
681 | conduitGet S.get $= | 780 | conduitGet S.get $= |
682 | trackFlow RemotePeer $= | 781 | trackFlow RemotePeer $= |
683 | action $= | 782 | action $= |
684 | trackFlow ThisPeer $$ | 783 | trackFlow ThisPeer C.$$ |
685 | sinkChan chan | 784 | sinkChan chan |
686 | 785 | ||
687 | -- | This function will block until a peer send new message. You can | 786 | -- | This function will block until a peer send new message. You can |
@@ -835,7 +934,7 @@ closePending PendingConnection {..} = do | |||
835 | 934 | ||
836 | chanToSock :: Int -> Chan Message -> Socket -> IO () | 935 | chanToSock :: Int -> Chan Message -> Socket -> IO () |
837 | chanToSock ka chan sock = | 936 | chanToSock ka chan sock = |
838 | sourceChan ka chan $= conduitPut S.put $$ sinkSocket sock | 937 | sourceChan ka chan $= conduitPut S.put C.$$ sinkSocket sock |
839 | 938 | ||
840 | afterHandshaking :: ChannelSide -> PeerAddr IP -> Socket -> HandshakePair | 939 | afterHandshaking :: ChannelSide -> PeerAddr IP -> Socket -> HandshakePair |
841 | -> ConnectionConfig s -> IO () | 940 | -> ConnectionConfig s -> IO () |
diff --git a/src/Network/BitTorrent/Exchange/Connection/Status.hs b/src/Network/BitTorrent/Exchange/Connection/Status.hs deleted file mode 100644 index f6abc580..00000000 --- a/src/Network/BitTorrent/Exchange/Connection/Status.hs +++ /dev/null | |||
@@ -1,131 +0,0 @@ | |||
1 | -- | | ||
2 | -- Copyright : (c) Sam Truzjan 2013 | ||
3 | -- License : BSD3 | ||
4 | -- Maintainer : pxqr.sta@gmail.com | ||
5 | -- Stability : experimental | ||
6 | -- Portability : portable | ||
7 | -- | ||
8 | -- Each P2P connection endpoint should keep track status of both | ||
9 | -- sides. | ||
10 | -- | ||
11 | {-# LANGUAGE TemplateHaskell #-} | ||
12 | module Network.BitTorrent.Exchange.Connection.Status | ||
13 | ( -- * Peer status | ||
14 | PeerStatus(..) | ||
15 | , choking | ||
16 | , interested | ||
17 | |||
18 | -- ** Query | ||
19 | , updateStatus | ||
20 | , statusUpdates | ||
21 | |||
22 | -- * Connection status | ||
23 | , ConnectionStatus(..) | ||
24 | , clientStatus | ||
25 | , remoteStatus | ||
26 | |||
27 | -- ** Query | ||
28 | , canUpload | ||
29 | , canDownload | ||
30 | |||
31 | -- * Extra | ||
32 | , defaultUnchokeSlots | ||
33 | , defaultRechokeInterval | ||
34 | ) where | ||
35 | |||
36 | import Control.Lens | ||
37 | import Data.Default | ||
38 | import Data.Maybe | ||
39 | import Data.Monoid | ||
40 | import Text.PrettyPrint as PP hiding ((<>)) | ||
41 | import Text.PrettyPrint.Class | ||
42 | |||
43 | import Network.BitTorrent.Exchange.Message | ||
44 | |||
45 | |||
46 | {----------------------------------------------------------------------- | ||
47 | -- Peer status | ||
48 | -----------------------------------------------------------------------} | ||
49 | |||
50 | -- | Connections contain two bits of state on either end: choked or | ||
51 | -- not, and interested or not. | ||
52 | data PeerStatus = PeerStatus | ||
53 | { -- | Choking is a notification that no data will be sent until | ||
54 | -- unchoking happens. | ||
55 | _choking :: !Bool | ||
56 | |||
57 | -- | | ||
58 | , _interested :: !Bool | ||
59 | } deriving (Show, Eq, Ord) | ||
60 | |||
61 | $(makeLenses ''PeerStatus) | ||
62 | |||
63 | instance Pretty PeerStatus where | ||
64 | pretty PeerStatus {..} = | ||
65 | pretty (Choking _choking) <+> "and" <+> pretty (Interested _interested) | ||
66 | |||
67 | -- | Connections start out choked and not interested. | ||
68 | instance Default PeerStatus where | ||
69 | def = PeerStatus True False | ||
70 | |||
71 | instance Monoid PeerStatus where | ||
72 | mempty = def | ||
73 | mappend a b = PeerStatus | ||
74 | { _choking = _choking a && _choking b | ||
75 | , _interested = _interested a || _interested b | ||
76 | } | ||
77 | |||
78 | -- | Can be used to update remote peer status using incoming 'Status' | ||
79 | -- message. | ||
80 | updateStatus :: StatusUpdate -> PeerStatus -> PeerStatus | ||
81 | updateStatus (Choking b) = choking .~ b | ||
82 | updateStatus (Interested b) = interested .~ b | ||
83 | |||
84 | -- | Can be used to generate outcoming messages. | ||
85 | statusUpdates :: PeerStatus -> PeerStatus -> [StatusUpdate] | ||
86 | statusUpdates a b = catMaybes $ | ||
87 | [ if _choking a == _choking b then Nothing | ||
88 | else Just $ Choking $ _choking b | ||
89 | , if _interested a == _interested b then Nothing | ||
90 | else Just $ Interested $ _interested b | ||
91 | ] | ||
92 | |||
93 | {----------------------------------------------------------------------- | ||
94 | -- Connection status | ||
95 | -----------------------------------------------------------------------} | ||
96 | |||
97 | -- | Status of the both endpoints. | ||
98 | data ConnectionStatus = ConnectionStatus | ||
99 | { _clientStatus :: !PeerStatus | ||
100 | , _remoteStatus :: !PeerStatus | ||
101 | } deriving (Show, Eq) | ||
102 | |||
103 | $(makeLenses ''ConnectionStatus) | ||
104 | |||
105 | instance Pretty ConnectionStatus where | ||
106 | pretty ConnectionStatus {..} = | ||
107 | "this " <+> pretty _clientStatus $$ | ||
108 | "remote" <+> pretty _remoteStatus | ||
109 | |||
110 | -- | Connections start out choked and not interested. | ||
111 | instance Default ConnectionStatus where | ||
112 | def = ConnectionStatus def def | ||
113 | |||
114 | -- | Can the client transfer to the remote peer? | ||
115 | canUpload :: ConnectionStatus -> Bool | ||
116 | canUpload ConnectionStatus {..} | ||
117 | = _interested _remoteStatus && not (_choking _clientStatus) | ||
118 | |||
119 | -- | Can the client transfer from the remote peer? | ||
120 | canDownload :: ConnectionStatus -> Bool | ||
121 | canDownload ConnectionStatus {..} | ||
122 | = _interested _clientStatus && not (_choking _remoteStatus) | ||
123 | |||
124 | -- | Indicates how many peers are allowed to download from the client | ||
125 | -- by default. | ||
126 | defaultUnchokeSlots :: Int | ||
127 | defaultUnchokeSlots = 4 | ||
128 | |||
129 | -- | | ||
130 | defaultRechokeInterval :: Int | ||
131 | defaultRechokeInterval = 10 * 1000 * 1000 \ No newline at end of file | ||
diff --git a/src/Network/BitTorrent/Exchange/Session.hs b/src/Network/BitTorrent/Exchange/Session.hs index 91ea8da9..6f480ce4 100644 --- a/src/Network/BitTorrent/Exchange/Session.hs +++ b/src/Network/BitTorrent/Exchange/Session.hs | |||
@@ -54,7 +54,6 @@ import Network.BitTorrent.Internal.Types | |||
54 | import Network.BitTorrent.Core | 54 | import Network.BitTorrent.Core |
55 | import Network.BitTorrent.Exchange.Block as Block | 55 | import Network.BitTorrent.Exchange.Block as Block |
56 | import Network.BitTorrent.Exchange.Connection | 56 | import Network.BitTorrent.Exchange.Connection |
57 | import Network.BitTorrent.Exchange.Connection.Status | ||
58 | import Network.BitTorrent.Exchange.Message as Message | 57 | import Network.BitTorrent.Exchange.Message as Message |
59 | import Network.BitTorrent.Exchange.Session.Metadata as Metadata | 58 | import Network.BitTorrent.Exchange.Session.Metadata as Metadata |
60 | import Network.BitTorrent.Exchange.Session.Status as SS | 59 | import Network.BitTorrent.Exchange.Session.Status as SS |