diff options
Diffstat (limited to 'src/Network/BitTorrent/Internal.hs')
-rw-r--r-- | src/Network/BitTorrent/Internal.hs | 67 |
1 files changed, 39 insertions, 28 deletions
diff --git a/src/Network/BitTorrent/Internal.hs b/src/Network/BitTorrent/Internal.hs index 918bfed7..db84e879 100644 --- a/src/Network/BitTorrent/Internal.hs +++ b/src/Network/BitTorrent/Internal.hs | |||
@@ -14,6 +14,7 @@ | |||
14 | -- data should be modified through standalone functions. | 14 | -- data should be modified through standalone functions. |
15 | -- | 15 | -- |
16 | {-# LANGUAGE OverloadedStrings #-} | 16 | {-# LANGUAGE OverloadedStrings #-} |
17 | {-# LANGUAGE BangPatterns #-} | ||
17 | {-# LANGUAGE RecordWildCards #-} | 18 | {-# LANGUAGE RecordWildCards #-} |
18 | {-# LANGUAGE TemplateHaskell #-} | 19 | {-# LANGUAGE TemplateHaskell #-} |
19 | {-# LANGUAGE DeriveDataTypeable #-} | 20 | {-# LANGUAGE DeriveDataTypeable #-} |
@@ -32,6 +33,7 @@ module Network.BitTorrent.Internal | |||
32 | 33 | ||
33 | -- * Swarm | 34 | -- * Swarm |
34 | , SwarmSession(SwarmSession, torrentMeta, clientSession) | 35 | , SwarmSession(SwarmSession, torrentMeta, clientSession) |
36 | , getSessionCount | ||
35 | , newLeacher, newSeeder | 37 | , newLeacher, newSeeder |
36 | , enterSwarm, leaveSwarm , waitVacancy | 38 | , enterSwarm, leaveSwarm , waitVacancy |
37 | 39 | ||
@@ -46,7 +48,6 @@ module Network.BitTorrent.Internal | |||
46 | , SessionException(..) | 48 | , SessionException(..) |
47 | , isSessionException | 49 | , isSessionException |
48 | , putSessionException | 50 | , putSessionException |
49 | , sessionError | ||
50 | 51 | ||
51 | -- ** Properties | 52 | -- ** Properties |
52 | , bitfield, status | 53 | , bitfield, status |
@@ -123,7 +124,7 @@ defaultThreadCount = 1000 | |||
123 | data ClientSession = ClientSession { | 124 | data ClientSession = ClientSession { |
124 | -- | Our peer ID used in handshaked and discovery mechanism. The | 125 | -- | Our peer ID used in handshaked and discovery mechanism. The |
125 | -- clientPeerID is unique 'ClientSession' identifier. | 126 | -- clientPeerID is unique 'ClientSession' identifier. |
126 | clientPeerID :: PeerID | 127 | clientPeerID :: !PeerID |
127 | 128 | ||
128 | -- | Extensions we should try to use. Hovewer some particular peer | 129 | -- | Extensions we should try to use. Hovewer some particular peer |
129 | -- might not support some extension, so we keep enableExtension in | 130 | -- might not support some extension, so we keep enableExtension in |
@@ -186,24 +187,31 @@ defLeacherConns = defaultNumWant | |||
186 | -- | Extensions are set globally by | 187 | -- | Extensions are set globally by |
187 | -- Swarm session are un | 188 | -- Swarm session are un |
188 | data SwarmSession = SwarmSession { | 189 | data SwarmSession = SwarmSession { |
189 | torrentMeta :: Torrent | 190 | torrentMeta :: !Torrent |
190 | , clientSession :: ClientSession | 191 | , clientSession :: !ClientSession |
191 | 192 | ||
192 | -- | Represent count of peers we _currently_ can connect to in the | 193 | -- | Represent count of peers we _currently_ can connect to in the |
193 | -- swarm. Used to bound number of concurrent threads. | 194 | -- swarm. Used to bound number of concurrent threads. |
194 | , vacantPeers :: MSem SessionCount | 195 | , vacantPeers :: !(MSem SessionCount) |
195 | 196 | ||
196 | -- | Modify this carefully updating global progress. | 197 | -- | Modify this carefully updating global progress. |
197 | , clientBitfield :: TVar Bitfield | 198 | , clientBitfield :: !(TVar Bitfield) |
198 | , connectedPeers :: TVar (Set PeerSession) | 199 | , connectedPeers :: !(TVar (Set PeerSession)) |
199 | } | 200 | } |
200 | 201 | ||
202 | -- INVARIANT: | ||
203 | -- max_sessions_count - sizeof connectedPeers = value vacantPeers | ||
204 | |||
201 | instance Eq SwarmSession where | 205 | instance Eq SwarmSession where |
202 | (==) = (==) `on` (tInfoHash . torrentMeta) | 206 | (==) = (==) `on` (tInfoHash . torrentMeta) |
203 | 207 | ||
204 | instance Ord SwarmSession where | 208 | instance Ord SwarmSession where |
205 | compare = comparing (tInfoHash . torrentMeta) | 209 | compare = comparing (tInfoHash . torrentMeta) |
206 | 210 | ||
211 | getSessionCount :: SwarmSession -> IO SessionCount | ||
212 | getSessionCount SwarmSession {..} = do | ||
213 | S.size <$> readTVarIO connectedPeers | ||
214 | |||
207 | newSwarmSession :: Int -> Bitfield -> ClientSession -> Torrent | 215 | newSwarmSession :: Int -> Bitfield -> ClientSession -> Torrent |
208 | -> IO SwarmSession | 216 | -> IO SwarmSession |
209 | newSwarmSession n bf cs @ ClientSession {..} t @ Torrent {..} | 217 | newSwarmSession n bf cs @ ClientSession {..} t @ Torrent {..} |
@@ -255,9 +263,9 @@ waitVacancy se = | |||
255 | data PeerSession = PeerSession { | 263 | data PeerSession = PeerSession { |
256 | -- | Used as unique 'PeerSession' identifier within one | 264 | -- | Used as unique 'PeerSession' identifier within one |
257 | -- 'SwarmSession'. | 265 | -- 'SwarmSession'. |
258 | connectedPeerAddr :: PeerAddr | 266 | connectedPeerAddr :: !PeerAddr |
259 | 267 | ||
260 | , swarmSession :: SwarmSession | 268 | , swarmSession :: !SwarmSession |
261 | 269 | ||
262 | -- | Extensions such that both peer and client support. | 270 | -- | Extensions such that both peer and client support. |
263 | , enabledExtensions :: [Extension] | 271 | , enabledExtensions :: [Extension] |
@@ -269,7 +277,7 @@ data PeerSession = PeerSession { | |||
269 | -- | 277 | -- |
270 | -- We should update timeout if we /receive/ any message within | 278 | -- We should update timeout if we /receive/ any message within |
271 | -- timeout interval to keep connection up. | 279 | -- timeout interval to keep connection up. |
272 | , incomingTimeout :: TimeoutKey | 280 | , incomingTimeout :: !TimeoutKey |
273 | 281 | ||
274 | -- | To send KA message appropriately we should know when was last | 282 | -- | To send KA message appropriately we should know when was last |
275 | -- time we sent a message to a peer. To do that we keep registered | 283 | -- time we sent a message to a peer. To do that we keep registered |
@@ -279,17 +287,17 @@ data PeerSession = PeerSession { | |||
279 | -- | 287 | -- |
280 | -- We should update timeout if we /send/ any message within timeout | 288 | -- We should update timeout if we /send/ any message within timeout |
281 | -- to avoid reduntant KA messages. | 289 | -- to avoid reduntant KA messages. |
282 | , outcomingTimeout :: TimeoutKey | 290 | , outcomingTimeout :: !TimeoutKey |
283 | 291 | ||
284 | -- TODO use dupChan for broadcasting | 292 | -- TODO use dupChan for broadcasting |
285 | , broadcastMessages :: Chan [Message] | 293 | , broadcastMessages :: !(Chan [Message]) |
286 | , sessionState :: IORef SessionState | 294 | , sessionState :: !(IORef SessionState) |
287 | } | 295 | } |
288 | 296 | ||
289 | data SessionState = SessionState { | 297 | data SessionState = SessionState { |
290 | _bitfield :: Bitfield | 298 | _bitfield :: !Bitfield |
291 | , _status :: SessionStatus | 299 | , _status :: !SessionStatus |
292 | } | 300 | } deriving (Show, Eq) |
293 | 301 | ||
294 | $(makeLenses ''SessionState) | 302 | $(makeLenses ''SessionState) |
295 | 303 | ||
@@ -301,10 +309,16 @@ instance Ord PeerSession where | |||
301 | 309 | ||
302 | instance (MonadIO m, MonadReader PeerSession m) | 310 | instance (MonadIO m, MonadReader PeerSession m) |
303 | => MonadState SessionState m where | 311 | => MonadState SessionState m where |
304 | get = asks sessionState >>= liftIO . readIORef | 312 | get = do |
305 | put s = asks sessionState >>= \ref -> liftIO $ writeIORef ref s | 313 | ref <- asks sessionState |
314 | st <- liftIO (readIORef ref) | ||
315 | liftIO $ print (completeness (_bitfield st)) | ||
316 | return st | ||
317 | |||
318 | put !s = asks sessionState >>= \ref -> liftIO $ writeIORef ref s | ||
306 | 319 | ||
307 | data SessionException = SessionException | 320 | data SessionException = PeerDisconnected |
321 | | ProtocolError Doc | ||
308 | deriving (Show, Typeable) | 322 | deriving (Show, Typeable) |
309 | 323 | ||
310 | instance Exception SessionException | 324 | instance Exception SessionException |
@@ -315,10 +329,6 @@ isSessionException _ = return () | |||
315 | putSessionException :: SessionException -> IO () | 329 | putSessionException :: SessionException -> IO () |
316 | putSessionException = print | 330 | putSessionException = print |
317 | 331 | ||
318 | sessionError :: MonadIO m => Doc -> m () | ||
319 | sessionError msg | ||
320 | = liftIO $ throwIO $ userError $ render $ msg <+> "in session" | ||
321 | |||
322 | -- TODO check if it connected yet peer | 332 | -- TODO check if it connected yet peer |
323 | withPeerSession :: SwarmSession -> PeerAddr | 333 | withPeerSession :: SwarmSession -> PeerAddr |
324 | -> ((Socket, PeerSession) -> IO ()) | 334 | -> ((Socket, PeerSession) -> IO ()) |
@@ -342,7 +352,7 @@ withPeerSession ss @ SwarmSession {..} addr | |||
342 | let enabled = decodeExts (enabledCaps caps (handshakeCaps phs)) | 352 | let enabled = decodeExts (enabledCaps caps (handshakeCaps phs)) |
343 | ps <- PeerSession addr ss enabled | 353 | ps <- PeerSession addr ss enabled |
344 | <$> registerTimeout (eventManager clientSession) | 354 | <$> registerTimeout (eventManager clientSession) |
345 | maxIncomingTime abortSession | 355 | maxIncomingTime (return ()) |
346 | <*> registerTimeout (eventManager clientSession) | 356 | <*> registerTimeout (eventManager clientSession) |
347 | maxOutcomingTime (sendKA sock) | 357 | maxOutcomingTime (sendKA sock) |
348 | <*> newChan | 358 | <*> newChan |
@@ -350,9 +360,13 @@ withPeerSession ss @ SwarmSession {..} addr | |||
350 | ; tc <- totalCount <$> readTVarIO clientBitfield | 360 | ; tc <- totalCount <$> readTVarIO clientBitfield |
351 | ; newIORef (SessionState (haveNone tc) def) | 361 | ; newIORef (SessionState (haveNone tc) def) |
352 | } | 362 | } |
363 | |||
364 | atomically $ modifyTVar' connectedPeers (S.insert ps) | ||
365 | |||
353 | return (sock, ps) | 366 | return (sock, ps) |
354 | 367 | ||
355 | closeSession (sock, _) = do | 368 | closeSession (sock, ps) = do |
369 | atomically $ modifyTVar' connectedPeers (S.delete ps) | ||
356 | close sock | 370 | close sock |
357 | 371 | ||
358 | getPieceCount :: (MonadReader PeerSession m) => m PieceCount | 372 | getPieceCount :: (MonadReader PeerSession m) => m PieceCount |
@@ -411,6 +425,3 @@ sendKA sock {- SwarmSession {..} -} = do | |||
411 | -- let mgr = eventManager clientSession | 425 | -- let mgr = eventManager clientSession |
412 | -- updateTimeout mgr | 426 | -- updateTimeout mgr |
413 | -- print "Done.." | 427 | -- print "Done.." |
414 | |||
415 | abortSession :: IO () | ||
416 | abortSession = error "abortSession: not implemented" | ||