summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2019-12-21 00:29:53 -0500
committerJoe Crayne <joe@jerkface.net>2020-01-01 23:27:49 -0500
commitca7f03b9b35ca1d47c51ed6b63c8d08a2b27b230 (patch)
tree624037e6edaa8c64ed3dc9a5a950f4e4a5aecba0
parentf5c9b738e489bced6189b85124952918414d8c8b (diff)
Bittorrent udp tracker server transport.
-rw-r--r--dht/src/Network/BitTorrent/Tracker/Message.hs8
-rw-r--r--dht/src/Network/BitTorrent/Tracker/Transport.hs76
-rw-r--r--dht/src/Network/QueryResponse.hs41
3 files changed, 109 insertions, 16 deletions
diff --git a/dht/src/Network/BitTorrent/Tracker/Message.hs b/dht/src/Network/BitTorrent/Tracker/Message.hs
index e9d12006..f44c7700 100644
--- a/dht/src/Network/BitTorrent/Tracker/Message.hs
+++ b/dht/src/Network/BitTorrent/Tracker/Message.hs
@@ -102,6 +102,7 @@ module Network.BitTorrent.Tracker.Message
102 102
103import Control.Applicative 103import Control.Applicative
104import Control.Monad 104import Control.Monad
105import Crypto.Random
105import Data.BEncode as BE hiding (Result) 106import Data.BEncode as BE hiding (Result)
106import Data.BEncode.BDict as BE 107import Data.BEncode.BDict as BE
107import Data.ByteString as BS 108import Data.ByteString as BS
@@ -810,8 +811,11 @@ newtype TransactionId = TransactionId Word32
810instance Show TransactionId where 811instance Show TransactionId where
811 showsPrec _ (TransactionId tid) = showString "0x" <> showHex tid 812 showsPrec _ (TransactionId tid) = showString "0x" <> showHex tid
812 813
813genTransactionId :: IO TransactionId 814genTransactionId :: DRG g => g -> (TransactionId, g)
814genTransactionId = (TransactionId . fromIntegral) <$> genToken 815genTransactionId g = let (ws, g') = randomBytesGenerate 4 g
816 Right w = S.runGet S.getWord32be ws
817 in (TransactionId w, g')
818
815 819
816data Request 820data Request
817 = Connect 821 = Connect
diff --git a/dht/src/Network/BitTorrent/Tracker/Transport.hs b/dht/src/Network/BitTorrent/Tracker/Transport.hs
new file mode 100644
index 00000000..60cb832d
--- /dev/null
+++ b/dht/src/Network/BitTorrent/Tracker/Transport.hs
@@ -0,0 +1,76 @@
1{-# LANGUAGE TupleSections #-}
2module Network.BitTorrent.Tracker.Transport where
3
4import Control.Concurrent.STM
5import Crypto.Random
6import Data.ByteString (ByteString)
7import Data.Functor.Contravariant
8import Data.IntMap.Strict (IntMap)
9import qualified Data.Serialize as S
10import Network.Socket
11
12import Data.QueryResponse.Table
13import Data.TableMethods
14import Network.Address
15import Network.BitTorrent.Tracker.Message
16import Network.QueryResponse as QR
17
18parseTracker :: ByteString -> SockAddr -> Either String (Transaction Request, SockAddr)
19parseTracker bs saddr = fmap (, saddr) $ S.decode bs
20
21encodeTracker :: Transaction Response -> SockAddr -> (ByteString, SockAddr)
22encodeTracker resp saddr = (S.encode resp,saddr)
23
24type Handler = MethodHandlerA String TransactionId SockAddr (Transaction Request) (Transaction Response)
25
26type Client = QR.ClientA String MessageId TransactionId SockAddr (Transaction Request) (Transaction Response)
27
28handlers :: MessageId -> Maybe Handler
29handlers ConnectId = Nothing
30handlers AnnounceId = Nothing
31handlers ScrapeId = Nothing
32handlers ErrorId = Nothing
33handlers _ = Nothing
34
35methodOfRequest :: Request -> MessageId
36methodOfRequest Connect {} = ConnectId
37methodOfRequest Announce {} = AnnounceId
38methodOfRequest Scrape {} = ScrapeId
39
40classify :: Transaction Request -> MessageClass String MessageId TransactionId SockAddr (Transaction Request)
41classify qry = IsQuery (methodOfRequest $ request qry) (transIdQ qry)
42
43dispatch :: DRG g =>
44 DispatchMethodsA
45 (g, IntMap (Maybe (Transaction Response) -> IO ()))
46 String
47 MessageId
48 TransactionId
49 SockAddr
50 (Transaction Request)
51 (Transaction Response)
52dispatch = DispatchMethods
53 { classifyInbound = classify
54 , lookupHandler = handlers
55 , tableMethods = transactionMethods (contramap fromEnum intMapMethods) genTransactionId
56 }
57
58newClient :: ErrorReporter SockAddr (Transaction Request) MessageId TransactionId String
59 -> TransportA String SockAddr (Transaction Request) (Transaction Response)
60 -> IO (ClientA String
61 MessageId
62 TransactionId
63 SockAddr
64 (Transaction Request)
65 (Transaction Response))
66newClient err net = do
67 drg <- drgNew
68 state <- newTVarIO (drg, mempty)
69 return QR.Client
70 { clientNet = net
71 , clientDispatcher = dispatch
72 , clientErrorReporter = err
73 , clientPending = state
74 , clientAddress = const $ return localhost4
75 , clientResponseId = return
76 }
diff --git a/dht/src/Network/QueryResponse.hs b/dht/src/Network/QueryResponse.hs
index 44039ee0..877c7ab6 100644
--- a/dht/src/Network/QueryResponse.hs
+++ b/dht/src/Network/QueryResponse.hs
@@ -271,12 +271,16 @@ data MessageClass err meth tid addr x
271 | IsUnknown err -- ^ None of the above. 271 | IsUnknown err -- ^ None of the above.
272 272
273-- | Handler for an inbound query of type /x/ from an address of type _addr_. 273-- | Handler for an inbound query of type /x/ from an address of type _addr_.
274data MethodHandler err tid addr x = forall a b. MethodHandler 274type MethodHandler err tid addr x = MethodHandlerA err tid addr x x
275
276-- | Handler for an inbound query of type /x/ with outbound response of type
277-- /y/ to an address of type /addr/.
278data MethodHandlerA err tid addr x y = forall a b. MethodHandler
275 { -- | Parse the query into a more specific type for this method. 279 { -- | Parse the query into a more specific type for this method.
276 methodParse :: x -> Either err a 280 methodParse :: x -> Either err a
277 -- | Serialize the response for transmission, given a context /ctx/ and the origin 281 -- | Serialize the response for transmission, given a context /ctx/ and the origin
278 -- and destination addresses. 282 -- and destination addresses.
279 , methodSerialize :: tid -> addr -> addr -> b -> x 283 , methodSerialize :: tid -> addr -> addr -> b -> y
280 -- | Fully typed action to perform upon the query. The remote origin 284 -- | Fully typed action to perform upon the query. The remote origin
281 -- address of the query is provided to the handler. 285 -- address of the query is provided to the handler.
282 , methodAction :: addr -> a -> IO b 286 , methodAction :: addr -> a -> IO b
@@ -290,49 +294,56 @@ data MethodHandler err tid addr x = forall a b. MethodHandler
290 , noreplyAction :: addr -> a -> IO () 294 , noreplyAction :: addr -> a -> IO ()
291 } 295 }
292 296
297
293-- | To dispatch responses to our outbound queries, we require three 298-- | To dispatch responses to our outbound queries, we require three
294-- primitives. See the 'transactionMethods' function to create these 299-- primitives. See the 'transactionMethods' function to create these
295-- primitives out of a lookup table and a generator for transaction ids. 300-- primitives out of a lookup table and a generator for transaction ids.
296-- 301--
297-- The type variable /d/ is used to represent the current state of the 302-- The type variable /d/ is used to represent the current state of the
298-- transaction generator and the table of pending transactions. 303-- transaction generator and the table of pending transactions.
299data TransactionMethods d qid addr x = TransactionMethods 304data TransactionMethods d qid addr y = TransactionMethods
300 { 305 {
301 -- | Before a query is sent, this function stores an 'MVar' to which the 306 -- | Before a query is sent, this function stores an 'MVar' to which the
302 -- response will be written too. The returned /qid/ is a transaction id 307 -- response will be written too. The returned /qid/ is a transaction id
303 -- that can be used to forget the 'MVar' if the remote peer is not 308 -- that can be used to forget the 'MVar' if the remote peer is not
304 -- responding. 309 -- responding.
305 dispatchRegister :: POSIXTime -- time of expiry 310 dispatchRegister :: POSIXTime -- time of expiry
306 -> (Maybe x -> IO ()) -- callback upon response (or timeout) 311 -> (Maybe y -> IO ()) -- callback upon response (or timeout)
307 -> addr 312 -> addr
308 -> d 313 -> d
309 -> STM (qid, d) 314 -> STM (qid, d)
310 -- | This method is invoked when an incoming packet /x/ indicates it is 315 -- | This method is invoked when an incoming packet /y/ indicates it is
311 -- a response to the transaction with id /qid/. The returned IO action 316 -- a response to the transaction with id /qid/. The returned IO action
312 -- will write the packet to the correct 'MVar' thus completing the 317 -- will write the packet to the correct 'MVar' thus completing the
313 -- dispatch. 318 -- dispatch.
314 , dispatchResponse :: qid -> x -> d -> STM (d, IO ()) 319 , dispatchResponse :: qid -> y -> d -> STM (d, IO ())
315 -- | When a timeout interval elapses, this method is called to remove the 320 -- | When a timeout interval elapses, this method is called to remove the
316 -- transaction from the table. 321 -- transaction from the table.
317 , dispatchCancel :: qid -> d -> STM d 322 , dispatchCancel :: qid -> d -> STM d
318 } 323 }
319 324
320-- | A set of methods necessary for dispatching incoming packets. 325-- | A set of methods necessary for dispatching incoming packets.
321data DispatchMethods tbl err meth tid addr x = DispatchMethods 326type DispatchMethods tbl err meth tid addr x = DispatchMethodsA tbl err meth tid addr x x
327
328-- | A set of methods necessary for dispatching incoming packets.
329data DispatchMethodsA tbl err meth tid addr x y = DispatchMethods
322 { -- | Classify an inbound packet as a query or response. 330 { -- | Classify an inbound packet as a query or response.
323 classifyInbound :: x -> MessageClass err meth tid addr x 331 classifyInbound :: x -> MessageClass err meth tid addr x
324 -- | Lookup the handler for a inbound query. 332 -- | Lookup the handler for a inbound query.
325 , lookupHandler :: meth -> Maybe (MethodHandler err tid addr x) 333 , lookupHandler :: meth -> Maybe (MethodHandlerA err tid addr x y)
326 -- | Methods for handling incoming responses. 334 -- | Methods for handling incoming responses.
327 , tableMethods :: TransactionMethods tbl tid addr x 335 , tableMethods :: TransactionMethods tbl tid addr y
328 } 336 }
329 337
330-- | All inputs required to implement a query\/response client. 338-- | All inputs required to implement a query\/response client.
331data Client err meth tid addr x = forall tbl. Client 339type Client err meth tid addr x = ClientA err meth tid addr x x
340
341-- | All inputs required to implement a query\/response client.
342data ClientA err meth tid addr x y = forall tbl. Client
332 { -- | The 'Transport' used to dispatch and receive packets. 343 { -- | The 'Transport' used to dispatch and receive packets.
333 clientNet :: Transport err addr x 344 clientNet :: TransportA err addr x y
334 -- | Methods for handling inbound packets. 345 -- | Methods for handling inbound packets.
335 , clientDispatcher :: DispatchMethods tbl err meth tid addr x 346 , clientDispatcher :: DispatchMethodsA tbl err meth tid addr x y
336 -- | Methods for reporting various conditions. 347 -- | Methods for reporting various conditions.
337 , clientErrorReporter :: ErrorReporter addr x meth tid err 348 , clientErrorReporter :: ErrorReporter addr x meth tid err
338 -- | State necessary for routing inbound responses and assigning unique 349 -- | State necessary for routing inbound responses and assigning unique
@@ -355,7 +366,7 @@ data Client err meth tid addr x = forall tbl. Client
355-- | These four parameters are required to implement an outgoing query. A 366-- | These four parameters are required to implement an outgoing query. A
356-- peer-to-peer algorithm will define a 'MethodSerializer' for every 'MethodHandler' that 367-- peer-to-peer algorithm will define a 'MethodSerializer' for every 'MethodHandler' that
357-- might be returned by 'lookupHandler'. 368-- might be returned by 'lookupHandler'.
358data MethodSerializer tid addr x meth a b = MethodSerializer 369data MethodSerializerA tid addr x y meth a b = MethodSerializer
359 { -- | Returns the microseconds to wait for a response to this query being 370 { -- | Returns the microseconds to wait for a response to this query being
360 -- sent to the given address. The /addr/ may also be modified to add 371 -- sent to the given address. The /addr/ may also be modified to add
361 -- routing information. 372 -- routing information.
@@ -369,9 +380,11 @@ data MethodSerializer tid addr x meth a b = MethodSerializer
369 -- auxiliary notations on all outgoing packets. 380 -- auxiliary notations on all outgoing packets.
370 , wrapQuery :: tid -> addr -> addr -> a -> x 381 , wrapQuery :: tid -> addr -> addr -> a -> x
371 -- | Parse an inbound packet /x/ into a response /b/ for this query. 382 -- | Parse an inbound packet /x/ into a response /b/ for this query.
372 , unwrapResponse :: x -> b 383 , unwrapResponse :: y -> b
373 } 384 }
374 385
386type MethodSerializer tid addr x meth a b = MethodSerializerA tid addr x x meth a b
387
375microsecondsDiff :: Int -> POSIXTime 388microsecondsDiff :: Int -> POSIXTime
376microsecondsDiff us = fromIntegral us / 1000000 389microsecondsDiff us = fromIntegral us / 1000000
377 390