diff options
Diffstat (limited to 'src/Network/BitTorrent/Exchange.hs')
-rw-r--r-- | src/Network/BitTorrent/Exchange.hs | 124 |
1 files changed, 89 insertions, 35 deletions
diff --git a/src/Network/BitTorrent/Exchange.hs b/src/Network/BitTorrent/Exchange.hs index 65ec0eb7..de13d4ce 100644 --- a/src/Network/BitTorrent/Exchange.hs +++ b/src/Network/BitTorrent/Exchange.hs | |||
@@ -18,7 +18,7 @@ module Network.BitTorrent.Exchange | |||
18 | , Event(..) | 18 | , Event(..) |
19 | 19 | ||
20 | , P2P, withPeer | 20 | , P2P, withPeer |
21 | , awaitEvent, signalEvent | 21 | , awaitEvent, yieldEvent |
22 | ) where | 22 | ) where |
23 | 23 | ||
24 | import Control.Applicative | 24 | import Control.Applicative |
@@ -70,29 +70,31 @@ runConduit sock p2p = | |||
70 | conduitPut S.put $$ | 70 | conduitPut S.put $$ |
71 | sinkSocket sock | 71 | sinkSocket sock |
72 | 72 | ||
73 | waitMessage :: P2P Message | 73 | awaitMessage :: P2P Message |
74 | waitMessage = P2P (ReaderT go) | 74 | awaitMessage = P2P (ReaderT go) |
75 | where | 75 | where |
76 | go se = do | 76 | go se = do |
77 | liftIO $ putStrLn "trying recv:" | ||
77 | mmsg <- await | 78 | mmsg <- await |
78 | case mmsg of | 79 | case mmsg of |
79 | Nothing -> go se | 80 | Nothing -> go se |
80 | Just msg -> do | 81 | Just msg -> do |
81 | liftIO $ updateIncoming se | 82 | -- liftIO $ updateIncoming se |
82 | liftIO $ print msg | 83 | liftIO $ print ("recv:" <+> ppMessage msg) |
83 | return msg | 84 | return msg |
84 | 85 | ||
85 | signalMessage :: Message -> P2P () | 86 | yieldMessage :: Message -> P2P () |
86 | signalMessage msg = P2P $ ReaderT $ \se -> do | 87 | yieldMessage msg = P2P $ ReaderT $ \se -> do |
87 | C.yield msg | 88 | C.yield msg |
89 | liftIO $ print $ "sent:" <+> ppMessage msg | ||
88 | liftIO $ updateOutcoming se | 90 | liftIO $ updateOutcoming se |
89 | 91 | ||
90 | 92 | ||
91 | peerWant :: P2P Bitfield | 93 | peerWant :: P2P Bitfield |
92 | peerWant = BF.difference <$> getPeerBF <*> use bitfield | 94 | peerWant = BF.difference <$> getClientBF <*> use bitfield |
93 | 95 | ||
94 | clientWant :: P2P Bitfield | 96 | clientWant :: P2P Bitfield |
95 | clientWant = BF.difference <$> use bitfield <*> getPeerBF | 97 | clientWant = BF.difference <$> use bitfield <*> getClientBF |
96 | 98 | ||
97 | peerOffer :: P2P Bitfield | 99 | peerOffer :: P2P Bitfield |
98 | peerOffer = do | 100 | peerOffer = do |
@@ -104,13 +106,17 @@ clientOffer = do | |||
104 | sessionStatus <- use status | 106 | sessionStatus <- use status |
105 | if canUpload sessionStatus then peerWant else emptyBF | 107 | if canUpload sessionStatus then peerWant else emptyBF |
106 | 108 | ||
107 | revise :: P2P () | 109 | revise :: P2P Bitfield |
108 | revise = do | 110 | revise = do |
109 | peerInteresting <- (not . BF.null) <$> clientWant | 111 | want <- clientWant |
112 | let peerInteresting = not (BF.null want) | ||
110 | clientInterested <- use (status.clientStatus.interested) | 113 | clientInterested <- use (status.clientStatus.interested) |
111 | 114 | ||
112 | when (clientInterested /= peerInteresting) $ | 115 | when (clientInterested /= peerInteresting) $ do |
113 | signalMessage $ if peerInteresting then Interested else NotInterested | 116 | yieldMessage $ if peerInteresting then Interested else NotInterested |
117 | status.clientStatus.interested .= peerInteresting | ||
118 | |||
119 | return want | ||
114 | 120 | ||
115 | requireExtension :: Extension -> P2P () | 121 | requireExtension :: Extension -> P2P () |
116 | requireExtension required = do | 122 | requireExtension required = do |
@@ -118,9 +124,6 @@ requireExtension required = do | |||
118 | unless (required `elem` enabled) $ | 124 | unless (required `elem` enabled) $ |
119 | sessionError $ ppExtension required <+> "not enabled" | 125 | sessionError $ ppExtension required <+> "not enabled" |
120 | 126 | ||
121 | peerHave :: P2P Event | ||
122 | peerHave = undefined | ||
123 | |||
124 | -- haveMessage bf = do | 127 | -- haveMessage bf = do |
125 | -- cbf <- undefined -- liftIO $ readIORef $ clientBitfield swarmSession | 128 | -- cbf <- undefined -- liftIO $ readIORef $ clientBitfield swarmSession |
126 | -- if undefined -- ix `member` bf | 129 | -- if undefined -- ix `member` bf |
@@ -129,12 +132,21 @@ peerHave = undefined | |||
129 | 132 | ||
130 | 133 | ||
131 | -- | | 134 | -- | |
135 | -- +----------+---------+ | ||
136 | -- | Leacher | Seeder | | ||
137 | -- |----------+---------+ | ||
138 | -- | Available| | | ||
139 | -- | Want | Want | | ||
140 | -- | Fragment | | | ||
141 | -- +----------+---------+ | ||
142 | -- | ||
143 | -- | ||
132 | -- properties: | 144 | -- properties: |
133 | -- | 145 | -- |
134 | -- forall (Fragment block). isPiece block == True | 146 | -- forall (Fragment block). isPiece block == True |
135 | -- | 147 | -- |
136 | awaitEvent :: P2P Event | 148 | awaitEvent :: P2P Event |
137 | awaitEvent = waitMessage >>= go | 149 | awaitEvent = awaitMessage >>= go |
138 | where | 150 | where |
139 | go KeepAlive = awaitEvent | 151 | go KeepAlive = awaitEvent |
140 | go Choke = do | 152 | go Choke = do |
@@ -142,8 +154,11 @@ awaitEvent = waitMessage >>= go | |||
142 | awaitEvent | 154 | awaitEvent |
143 | 155 | ||
144 | go Unchoke = do | 156 | go Unchoke = do |
145 | status.clientStatus.choking .= False | 157 | status.peerStatus.choking .= False |
146 | awaitEvent | 158 | offer <- peerOffer |
159 | if BF.null offer | ||
160 | then awaitEvent | ||
161 | else return (Available offer) | ||
147 | 162 | ||
148 | go Interested = do | 163 | go Interested = do |
149 | status.peerStatus.interested .= True | 164 | status.peerStatus.interested .= True |
@@ -153,21 +168,45 @@ awaitEvent = waitMessage >>= go | |||
153 | status.peerStatus.interested .= False | 168 | status.peerStatus.interested .= False |
154 | awaitEvent | 169 | awaitEvent |
155 | 170 | ||
156 | -- go (Have ix) = peerHave =<< singletonBF ix | 171 | go (Have ix) = do |
157 | -- go (Bitfield bf) = peerHave =<< adjustBF bf | 172 | new <- singletonBF ix |
173 | bitfield %= BF.union new | ||
174 | revise | ||
175 | |||
176 | offer <- peerOffer | ||
177 | if not (BF.null offer) | ||
178 | then return (Available offer) | ||
179 | else awaitEvent | ||
180 | |||
181 | go (Bitfield bf) = do | ||
182 | new <- adjustBF bf | ||
183 | bitfield .= new | ||
184 | revise | ||
185 | |||
186 | offer <- peerOffer | ||
187 | if not (BF.null offer) | ||
188 | then return (Available offer) | ||
189 | else awaitEvent | ||
190 | |||
158 | go (Request bix) = do | 191 | go (Request bix) = do |
159 | bf <- use bitfield | 192 | bf <- clientOffer |
160 | if ixPiece bix `BF.member` bf | 193 | if ixPiece bix `BF.member` bf |
161 | then return (Want bix) | 194 | then return (Want bix) |
162 | else do | 195 | else do |
163 | signalMessage (RejectRequest bix) | 196 | -- check if extension is enabled |
197 | -- yieldMessage (RejectRequest bix) | ||
164 | awaitEvent | 198 | awaitEvent |
165 | 199 | ||
166 | go (Piece blk) = undefined | 200 | go (Piece blk) = do |
201 | -- this protect us from malicious peers and duplication | ||
202 | wanted <- clientWant | ||
203 | if blkPiece blk `BF.member` wanted | ||
204 | then return (Fragment blk) | ||
205 | else awaitEvent | ||
167 | 206 | ||
168 | {- | 207 | {- |
169 | go msg @ (Port _) | 208 | go (Port _) = do |
170 | = checkExtension msg ExtDHT $ do | 209 | requireExtension ExtDHT |
171 | undefined | 210 | undefined |
172 | 211 | ||
173 | go HaveAll = do | 212 | go HaveAll = do |
@@ -189,24 +228,39 @@ awaitEvent = waitMessage >>= go | |||
189 | then Available <$> singletonBF ix | 228 | then Available <$> singletonBF ix |
190 | else awaitEvent | 229 | else awaitEvent |
191 | 230 | ||
192 | go msg @ (RejectRequest ix) | 231 | go (RejectRequest ix) = do |
193 | = checkExtension msg ExtFast $ do | 232 | requireExtension ExtFast |
194 | undefined | 233 | awaitMessage |
195 | 234 | ||
196 | go msg @ (AllowedFast pix) | 235 | go (AllowedFast pix) = |
197 | = checkExtension msg ExtFast $ do | 236 | requireExtension ExtFast |
198 | undefined | 237 | awaitMessage |
199 | -} | 238 | -} |
200 | 239 | ||
201 | signalEvent :: Event -> P2P () | 240 | |
202 | signalEvent (Available bf) = undefined | 241 | -- | |
203 | signalEvent _ = undefined | 242 | -- @ |
243 | -- +----------+---------+ | ||
244 | -- | Leacher | Seeder | | ||
245 | -- |----------+---------+ | ||
246 | -- | Available| | | ||
247 | -- | Want |Fragment | | ||
248 | -- | Fragment | | | ||
249 | -- +----------+---------+ | ||
250 | -- @ | ||
251 | -- | ||
252 | yieldEvent :: Event -> P2P () | ||
253 | yieldEvent (Available bf) = undefined | ||
254 | yieldEvent _ = undefined | ||
204 | 255 | ||
205 | --flushBroadcast :: P2P () | 256 | --flushBroadcast :: P2P () |
206 | --flushBroadcast = nextBroadcast >>= maybe (return ()) go | 257 | --flushBroadcast = nextBroadcast >>= maybe (return ()) go |
207 | -- where | 258 | -- where |
208 | -- go = undefined | 259 | -- go = undefined |
209 | 260 | ||
261 | checkPiece :: PieceLIx -> {-ByteString -> -} P2P Bool | ||
262 | checkPiece = undefined | ||
263 | |||
210 | {----------------------------------------------------------------------- | 264 | {----------------------------------------------------------------------- |
211 | P2P monad | 265 | P2P monad |
212 | -----------------------------------------------------------------------} | 266 | -----------------------------------------------------------------------} |