summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent/Internal.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/BitTorrent/Internal.hs')
-rw-r--r--src/Network/BitTorrent/Internal.hs67
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
123data ClientSession = ClientSession { 124data 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
188data SwarmSession = SwarmSession { 189data 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
201instance Eq SwarmSession where 205instance Eq SwarmSession where
202 (==) = (==) `on` (tInfoHash . torrentMeta) 206 (==) = (==) `on` (tInfoHash . torrentMeta)
203 207
204instance Ord SwarmSession where 208instance Ord SwarmSession where
205 compare = comparing (tInfoHash . torrentMeta) 209 compare = comparing (tInfoHash . torrentMeta)
206 210
211getSessionCount :: SwarmSession -> IO SessionCount
212getSessionCount SwarmSession {..} = do
213 S.size <$> readTVarIO connectedPeers
214
207newSwarmSession :: Int -> Bitfield -> ClientSession -> Torrent 215newSwarmSession :: Int -> Bitfield -> ClientSession -> Torrent
208 -> IO SwarmSession 216 -> IO SwarmSession
209newSwarmSession n bf cs @ ClientSession {..} t @ Torrent {..} 217newSwarmSession n bf cs @ ClientSession {..} t @ Torrent {..}
@@ -255,9 +263,9 @@ waitVacancy se =
255data PeerSession = PeerSession { 263data 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
289data SessionState = SessionState { 297data 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
302instance (MonadIO m, MonadReader PeerSession m) 310instance (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
307data SessionException = SessionException 320data SessionException = PeerDisconnected
321 | ProtocolError Doc
308 deriving (Show, Typeable) 322 deriving (Show, Typeable)
309 323
310instance Exception SessionException 324instance Exception SessionException
@@ -315,10 +329,6 @@ isSessionException _ = return ()
315putSessionException :: SessionException -> IO () 329putSessionException :: SessionException -> IO ()
316putSessionException = print 330putSessionException = print
317 331
318sessionError :: MonadIO m => Doc -> m ()
319sessionError 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
323withPeerSession :: SwarmSession -> PeerAddr 333withPeerSession :: 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
358getPieceCount :: (MonadReader PeerSession m) => m PieceCount 372getPieceCount :: (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
415abortSession :: IO ()
416abortSession = error "abortSession: not implemented"