diff options
Diffstat (limited to 'src/Network')
-rw-r--r-- | src/Network/BitTorrent/Exchange/Wire.hs | 79 |
1 files changed, 74 insertions, 5 deletions
diff --git a/src/Network/BitTorrent/Exchange/Wire.hs b/src/Network/BitTorrent/Exchange/Wire.hs index baf76e5f..9b83590a 100644 --- a/src/Network/BitTorrent/Exchange/Wire.hs +++ b/src/Network/BitTorrent/Exchange/Wire.hs | |||
@@ -29,6 +29,9 @@ module Network.BitTorrent.Exchange.Wire | |||
29 | -- ** Flood detection | 29 | -- ** Flood detection |
30 | , FloodDetector (..) | 30 | , FloodDetector (..) |
31 | 31 | ||
32 | -- ** Options | ||
33 | , Options (..) | ||
34 | |||
32 | -- ** Connection | 35 | -- ** Connection |
33 | , Connection | 36 | , Connection |
34 | , connProtocol | 37 | , connProtocol |
@@ -36,6 +39,7 @@ module Network.BitTorrent.Exchange.Wire | |||
36 | , connTopic | 39 | , connTopic |
37 | , connRemotePeerId | 40 | , connRemotePeerId |
38 | , connThisPeerId | 41 | , connThisPeerId |
42 | , connOptions | ||
39 | 43 | ||
40 | -- ** Setup | 44 | -- ** Setup |
41 | , runWire | 45 | , runWire |
@@ -136,7 +140,7 @@ data ProtocolError | |||
136 | -- | 'Network.BitTorrent.Exchange.Message.Bitfield' message MUST | 140 | -- | 'Network.BitTorrent.Exchange.Message.Bitfield' message MUST |
137 | -- be send either once or zero times, but either this peer or | 141 | -- be send either once or zero times, but either this peer or |
138 | -- remote peer send a bitfield message the second time. | 142 | -- remote peer send a bitfield message the second time. |
139 | | BitfieldAlreadySend ChannelSide | 143 | | BitfieldAlreadySent ChannelSide |
140 | 144 | ||
141 | -- | Capabilities violation. For example this exception can occur | 145 | -- | Capabilities violation. For example this exception can occur |
142 | -- when a peer have sent 'Port' message but 'ExtDHT' is not | 146 | -- when a peer have sent 'Port' message but 'ExtDHT' is not |
@@ -331,20 +335,81 @@ data FloodDetector = FloodDetector | |||
331 | , floodThreshold :: {-# UNPACK #-} !Int | 335 | , floodThreshold :: {-# UNPACK #-} !Int |
332 | 336 | ||
333 | -- | Flood predicate on the /current/ 'ConnectionStats'. | 337 | -- | Flood predicate on the /current/ 'ConnectionStats'. |
334 | , floodDetector :: Detector ConnectionStats | 338 | , floodPredicate :: Detector ConnectionStats |
335 | } deriving Show | 339 | } deriving Show |
336 | 340 | ||
337 | 341 | -- | Flood detector with very permissive options. | |
338 | instance Default FloodDetector where | 342 | instance Default FloodDetector where |
339 | def = FloodDetector | 343 | def = FloodDetector |
340 | { floodFactor = defaultFloodFactor | 344 | { floodFactor = defaultFloodFactor |
341 | , floodThreshold = defaultFloodThreshold | 345 | , floodThreshold = defaultFloodThreshold |
342 | , floodDetector = defaultDetector | 346 | , floodPredicate = defaultDetector |
343 | } | 347 | } |
344 | 348 | ||
345 | -- | This peer might drop connection if the detector gives positive answer. | 349 | -- | This peer might drop connection if the detector gives positive answer. |
346 | runDetector :: FloodDetector -> ConnectionStats -> Bool | 350 | runDetector :: FloodDetector -> ConnectionStats -> Bool |
347 | runDetector FloodDetector {..} = floodDetector floodFactor floodThreshold | 351 | runDetector FloodDetector {..} = floodPredicate floodFactor floodThreshold |
352 | |||
353 | {----------------------------------------------------------------------- | ||
354 | -- Options | ||
355 | -----------------------------------------------------------------------} | ||
356 | |||
357 | -- | Various connection settings and limits. | ||
358 | data Options = Options | ||
359 | { -- | How often /this/ peer should send 'KeepAlive' messages. | ||
360 | keepaliveInterval :: {-# UNPACK #-} !Int | ||
361 | |||
362 | -- | /This/ peer will drop connection if a /remote/ peer did not | ||
363 | -- send any message for this period of time. | ||
364 | , keepaliveTimeout :: {-# UNPACK #-} !Int | ||
365 | |||
366 | -- | Used to protect against flood attacks. | ||
367 | , floodDetector :: FloodDetector | ||
368 | |||
369 | -- | Used to protect against flood attacks in /metadata | ||
370 | -- exchange/. Normally, a requesting peer should request each | ||
371 | -- 'InfoDict' piece only one time, but a malicious peer can | ||
372 | -- saturate wire with 'MetadataRequest' messages thus flooding | ||
373 | -- responding peer. | ||
374 | -- | ||
375 | -- This value set upper bound for number of 'MetadataRequests' | ||
376 | -- for each piece. | ||
377 | -- | ||
378 | , metadataFactor :: {-# UNPACK #-} !Int | ||
379 | |||
380 | -- | Used to protect against out-of-memory attacks: malicious peer | ||
381 | -- can claim that 'totalSize' is, say, 100TB and send some random | ||
382 | -- data instead of infodict pieces. Since requesting peer unable | ||
383 | -- to check not completed infodict via the infohash, the | ||
384 | -- accumulated pieces will allocate the all available memory. | ||
385 | -- | ||
386 | -- This limit set upper bound for 'InfoDict' size. See | ||
387 | -- 'ExtendedMetadata' for more info. | ||
388 | -- | ||
389 | , maxInfoDictSize :: {-# UNPACK #-} !Int | ||
390 | } deriving Show | ||
391 | |||
392 | -- | Allows a requesting peer to send 2 'MetadataRequest's for the | ||
393 | -- each piece. | ||
394 | defaultMetadataFactor :: Int | ||
395 | defaultMetadataFactor = 2 | ||
396 | |||
397 | -- | Usually torrent size do not exceed 1MB. This value limit torrent | ||
398 | -- /content/ size to about 8TB. See 'maxInfoDictSize' for explanation | ||
399 | -- why do we need this limit. | ||
400 | defaultMaxInfoDictSize :: Int | ||
401 | defaultMaxInfoDictSize = 10 * 1024 * 1024 | ||
402 | |||
403 | -- | Permissive default parameters, most likely you don't need to | ||
404 | -- change them. | ||
405 | instance Default Options where | ||
406 | def = Options | ||
407 | { keepaliveInterval = defaultKeepAliveInterval | ||
408 | , keepaliveTimeout = defaultKeepAliveTimeout | ||
409 | , floodDetector = def | ||
410 | , metadataFactor = defaultMetadataFactor | ||
411 | , maxInfoDictSize = defaultMaxInfoDictSize | ||
412 | } | ||
348 | 413 | ||
349 | {----------------------------------------------------------------------- | 414 | {----------------------------------------------------------------------- |
350 | -- Connection | 415 | -- Connection |
@@ -372,6 +437,9 @@ data Connection = Connection | |||
372 | -- | Typically extracted from handshake. | 437 | -- | Typically extracted from handshake. |
373 | , connThisPeerId :: !PeerId | 438 | , connThisPeerId :: !PeerId |
374 | 439 | ||
440 | -- | | ||
441 | , connOptions :: !Options | ||
442 | |||
375 | -- | If @not (allowed ExtExtended connCaps)@ then this set is | 443 | -- | If @not (allowed ExtExtended connCaps)@ then this set is |
376 | -- always empty. Otherwise it has extension protocol 'MessageId' | 444 | -- always empty. Otherwise it has extension protocol 'MessageId' |
377 | -- map. | 445 | -- map. |
@@ -581,6 +649,7 @@ connectWire hs addr extCaps wire = | |||
581 | , connTopic = hsInfoHash hs | 649 | , connTopic = hsInfoHash hs |
582 | , connRemotePeerId = hsPeerId hs' | 650 | , connRemotePeerId = hsPeerId hs' |
583 | , connThisPeerId = hsPeerId hs | 651 | , connThisPeerId = hsPeerId hs |
652 | , connOptions = def | ||
584 | , connExtCaps = extCapsRef | 653 | , connExtCaps = extCapsRef |
585 | , connStats = statsRef | 654 | , connStats = statsRef |
586 | } | 655 | } |