diff options
Diffstat (limited to 'src/Network')
-rw-r--r-- | src/Network/BitTorrent/DHT.hs | 6 | ||||
-rw-r--r-- | src/Network/BitTorrent/DHT/Query.hs | 103 | ||||
-rw-r--r-- | src/Network/DHT.hs | 2 | ||||
-rw-r--r-- | src/Network/DHT/Types.hs | 2 | ||||
-rw-r--r-- | src/Network/DatagramServer.hs | 20 | ||||
-rw-r--r-- | src/Network/DatagramServer/Mainline.hs | 23 | ||||
-rw-r--r-- | src/Network/DatagramServer/Tox.hs | 118 | ||||
-rw-r--r-- | src/Network/DatagramServer/Types.hs | 33 |
8 files changed, 255 insertions, 52 deletions
diff --git a/src/Network/BitTorrent/DHT.hs b/src/Network/BitTorrent/DHT.hs index fa8071d5..2535c05c 100644 --- a/src/Network/BitTorrent/DHT.hs +++ b/src/Network/BitTorrent/DHT.hs | |||
@@ -234,7 +234,7 @@ bootstrap :: forall raw dht u ip. | |||
234 | , Show u | 234 | , Show u |
235 | , Default u | 235 | , Default u |
236 | , Serialize u | 236 | , Serialize u |
237 | ) => Maybe BS.ByteString -> [NodeAddr ip] -> DHT raw dht u ip () | 237 | ) => Maybe BS.ByteString -> [PacketDestination dht] -> DHT raw dht u ip () |
238 | bootstrap mbs startNodes = do | 238 | bootstrap mbs startNodes = do |
239 | restored <- | 239 | restored <- |
240 | case decode <$> mbs of | 240 | case decode <$> mbs of |
@@ -250,7 +250,7 @@ bootstrap mbs startNodes = do | |||
250 | return ( ns :: [NodeInfo dht ip u] ) | 250 | return ( ns :: [NodeInfo dht ip u] ) |
251 | input_nodes <- (restored ++) . T.toList <$> getTable | 251 | input_nodes <- (restored ++) . T.toList <$> getTable |
252 | -- Step 1: Use iterative searches to flesh out the table.. | 252 | -- Step 1: Use iterative searches to flesh out the table.. |
253 | do let knowns = map (map $ nodeAddr . fst) input_nodes | 253 | do let knowns = map (map $ fst) input_nodes |
254 | -- Below, we reverse the nodes since the table serialization puts the | 254 | -- Below, we reverse the nodes since the table serialization puts the |
255 | -- nearest nodes last and we want to choose a similar node id to bootstrap | 255 | -- nearest nodes last and we want to choose a similar node id to bootstrap |
256 | -- faster. | 256 | -- faster. |
@@ -265,7 +265,7 @@ bootstrap mbs startNodes = do | |||
265 | when (null ns) $ do | 265 | when (null ns) $ do |
266 | -- TODO filter duplicated in startNodes list | 266 | -- TODO filter duplicated in startNodes list |
267 | -- TODO retransmissions for startNodes | 267 | -- TODO retransmissions for startNodes |
268 | (aliveNodes,_) <- unzip <$> queryParallel (pingQ <$> startNodes) | 268 | (aliveNodes,_) <- unzip <$> queryParallel (coldPingQ <$> startNodes) |
269 | _ <- searchAll $ take 2 aliveNodes | 269 | _ <- searchAll $ take 2 aliveNodes |
270 | return () | 270 | return () |
271 | -- Step 2: Repeatedly refresh incomplete buckets until the table is full. | 271 | -- Step 2: Repeatedly refresh incomplete buckets until the table is full. |
diff --git a/src/Network/BitTorrent/DHT/Query.hs b/src/Network/BitTorrent/DHT/Query.hs index 77fede94..60b772b3 100644 --- a/src/Network/BitTorrent/DHT/Query.hs +++ b/src/Network/BitTorrent/DHT/Query.hs | |||
@@ -35,6 +35,7 @@ module Network.BitTorrent.DHT.Query | |||
35 | -- single response. | 35 | -- single response. |
36 | , Iteration | 36 | , Iteration |
37 | , pingQ | 37 | , pingQ |
38 | , coldPingQ | ||
38 | , findNodeQ | 39 | , findNodeQ |
39 | , getPeersQ | 40 | , getPeersQ |
40 | , announceQ | 41 | , announceQ |
@@ -316,44 +317,72 @@ pingQ :: forall raw dht u ip. | |||
316 | , FiniteBits (NodeId dht) | 317 | , FiniteBits (NodeId dht) |
317 | , Show (NodeId dht) | 318 | , Show (NodeId dht) |
318 | , Show (QueryMethod dht) | 319 | , Show (QueryMethod dht) |
319 | ) => NodeAddr ip -> DHT raw dht u ip (NodeInfo dht ip u , Maybe ReflectedIP) | 320 | ) => NodeInfo dht ip u -> DHT raw dht u ip (NodeInfo dht ip u , Maybe ReflectedIP) |
320 | pingQ addr = do | 321 | pingQ ni = do |
321 | let ping = DHT.pingMessage (Proxy :: Proxy dht) | 322 | let ping = DHT.pingMessage (Proxy :: Proxy dht) |
322 | (nid, pong, mip) <- queryNode' addr ping | 323 | (nid, pong, mip) <- queryNode' ni ping |
323 | let _ = pong `asTypeOf` ping | 324 | let _ = pong `asTypeOf` ping |
324 | -- (nid, PingPayload{}, mip) <- queryNode' addr PingPayload {isPong=False, pingId=pid} | 325 | -- (nid, PingPayload{}, mip) <- queryNode' addr PingPayload {isPong=False, pingId=pid} |
325 | return (NodeInfo nid addr def, mip) | 326 | return (NodeInfo nid (nodeAddr ni) def, mip) |
327 | |||
328 | -- | The most basic query. May be used to check if the given node is | ||
329 | -- alive or get its 'NodeId'. | ||
330 | coldPingQ :: forall raw dht u ip. | ||
331 | ( DHT.Kademlia dht | ||
332 | , Address ip | ||
333 | , KRPC dht (Query dht (Ping dht)) (Response dht (Ping dht)) | ||
334 | , Default u | ||
335 | , Show u | ||
336 | , Ord (TransactionID dht) | ||
337 | , Serialize (TransactionID dht) | ||
338 | , WireFormat raw dht | ||
339 | , SerializableTo raw (Response dht (Ping dht)) | ||
340 | , SerializableTo raw (Query dht (Ping dht)) | ||
341 | , Ord (NodeId dht) | ||
342 | , FiniteBits (NodeId dht) | ||
343 | , Show (NodeId dht) | ||
344 | , Show (QueryMethod dht) | ||
345 | ) => PacketDestination dht -> DHT raw dht u ip (NodeInfo dht ip u , Maybe ReflectedIP) | ||
346 | coldPingQ dest = do | ||
347 | let ping = DHT.pingMessage (Proxy :: Proxy dht) | ||
348 | naddr <- maybe (throwIO $ QueryFailed ProtocolError "unable to construct NodeAddr from PacketDestination") | ||
349 | return | ||
350 | $ fromAddr dest | ||
351 | (nid, pong, mip) <- coldQueryNode' naddr dest ping | ||
352 | let _ = pong `asTypeOf` ping | ||
353 | -- (nid, PingPayload{}, mip) <- queryNode' addr PingPayload {isPong=False, pingId=pid} | ||
354 | return (NodeInfo nid naddr def, mip) | ||
326 | 355 | ||
327 | -- TODO [robustness] match range of returned node ids with the | 356 | -- TODO [robustness] match range of returned node ids with the |
328 | -- expected range and either filter bad nodes or discard response at | 357 | -- expected range and either filter bad nodes or discard response at |
329 | -- all throwing an exception | 358 | -- all throwing an exception |
330 | -- findNodeQ :: Address ip => TableKey key => key -> IterationI ip NodeInfo | 359 | -- findNodeQ :: Address ip => TableKey key => key -> IterationI ip NodeInfo |
331 | findNodeQ proxy key NodeInfo {..} = do | 360 | findNodeQ proxy key ni = do |
332 | closest <- fmap DHT.foundNodes $ DHT.findNodeMessage proxy key <@> nodeAddr | 361 | closest <- fmap DHT.foundNodes $ DHT.findNodeMessage proxy key <@> ni |
333 | $(logInfoS) "findNodeQ" $ "NodeFound\n" | 362 | $(logInfoS) "findNodeQ" $ "NodeFound\n" |
334 | <> T.pack (L.unlines $ L.map ((' ' :) . show . pPrint) closest) | 363 | <> T.pack (L.unlines $ L.map ((' ' :) . show . pPrint) closest) |
335 | return $ Right closest | 364 | return $ Right closest |
336 | 365 | ||
337 | #ifdef VERSION_bencoding | 366 | #ifdef VERSION_bencoding |
338 | getPeersQ :: Address ip => InfoHash -> Iteration BValue KMessageOf () ip PeerAddr | 367 | getPeersQ :: Address ip => InfoHash -> Iteration BValue KMessageOf () ip PeerAddr |
339 | getPeersQ topic NodeInfo {..} = do | 368 | getPeersQ topic ni = do |
340 | GotPeers {..} <- GetPeers topic <@> nodeAddr | 369 | GotPeers {..} <- GetPeers topic <@> ni |
341 | let dist = distance (toNodeId topic) nodeId | 370 | let dist = distance (toNodeId topic) (nodeId ni) |
342 | $(logInfoS) "getPeersQ" $ T.pack | 371 | $(logInfoS) "getPeersQ" $ T.pack |
343 | $ "distance: " <> render (pPrint dist) <> " , result: " | 372 | $ "distance: " <> render (pPrint dist) <> " , result: " |
344 | <> case peers of { Left _ -> "NODES"; Right _ -> "PEERS" } | 373 | <> case peers of { Left _ -> "NODES"; Right _ -> "PEERS" } |
345 | return peers | 374 | return peers |
346 | 375 | ||
347 | announceQ :: Address ip => InfoHash -> PortNumber -> Iteration BValue KMessageOf () ip NodeAddr | 376 | announceQ :: Address ip => InfoHash -> PortNumber -> Iteration BValue KMessageOf () ip NodeAddr |
348 | announceQ ih p NodeInfo {..} = do | 377 | announceQ ih p ni = do |
349 | GotPeers {..} <- GetPeers ih <@> nodeAddr | 378 | GotPeers {..} <- GetPeers ih <@> ni |
350 | case peers of | 379 | case peers of |
351 | Left ns | 380 | Left ns |
352 | | False -> undefined -- TODO check if we can announce | 381 | | False -> undefined -- TODO check if we can announce |
353 | | otherwise -> return (Left ns) | 382 | | otherwise -> return (Left ns) |
354 | Right _ -> do -- TODO *probably* add to peer cache | 383 | Right _ -> do -- TODO *probably* add to peer cache |
355 | Announced <- Announce False ih Nothing p grantedToken <@> nodeAddr | 384 | Announced <- Announce False ih Nothing p grantedToken <@> ni |
356 | return (Right [nodeAddr]) | 385 | return (Right [nodeAddr ni]) |
357 | #endif | 386 | #endif |
358 | 387 | ||
359 | {----------------------------------------------------------------------- | 388 | {----------------------------------------------------------------------- |
@@ -393,7 +422,7 @@ ioFindNode :: ( DHT.Kademlia dht | |||
393 | ioFindNode ih = do | 422 | ioFindNode ih = do |
394 | session <- ask | 423 | session <- ask |
395 | return $ \ni -> runDHT session $ do | 424 | return $ \ni -> runDHT session $ do |
396 | ns <- fmap DHT.foundNodes $ DHT.findNodeMessage Proxy ih <@> nodeAddr ni | 425 | ns <- fmap DHT.foundNodes $ DHT.findNodeMessage Proxy ih <@> ni |
397 | let ns' = L.map (fmap (const def)) ns | 426 | let ns' = L.map (fmap (const def)) ns |
398 | return $ L.partition (\n -> nodeId n /= toNodeId ih) ns' | 427 | return $ L.partition (\n -> nodeId n /= toNodeId ih) ns' |
399 | 428 | ||
@@ -422,7 +451,7 @@ ioFindNodes :: ( DHT.Kademlia dht | |||
422 | ioFindNodes ih = do | 451 | ioFindNodes ih = do |
423 | session <- ask | 452 | session <- ask |
424 | return $ \ni -> runDHT session $ do | 453 | return $ \ni -> runDHT session $ do |
425 | ns <- fmap DHT.foundNodes $ DHT.findNodeMessage Proxy ih <@> nodeAddr ni | 454 | ns <- fmap DHT.foundNodes $ DHT.findNodeMessage Proxy ih <@> ni |
426 | let ns' = L.map (fmap (const def)) ns | 455 | let ns' = L.map (fmap (const def)) ns |
427 | return ([], ns') | 456 | return ([], ns') |
428 | 457 | ||
@@ -504,9 +533,9 @@ probeNode :: ( Default u | |||
504 | , FiniteBits (NodeId dht) | 533 | , FiniteBits (NodeId dht) |
505 | , Show (NodeId dht) | 534 | , Show (NodeId dht) |
506 | , Show (QueryMethod dht) | 535 | , Show (QueryMethod dht) |
507 | ) => NodeAddr ip -> DHT raw dht u ip (Bool , Maybe ReflectedIP) | 536 | ) => NodeInfo dht ip u -> DHT raw dht u ip (Bool , Maybe ReflectedIP) |
508 | probeNode addr = do | 537 | probeNode addr = do |
509 | $(logDebugS) "routing.questionable_node" (T.pack (render (pPrint addr))) | 538 | $(logDebugS) "routing.questionable_node" (T.pack (render (pPrint $ nodeAddr addr))) |
510 | result <- try $ pingQ addr | 539 | result <- try $ pingQ addr |
511 | let _ = fmap (const ()) result :: Either QueryFailure () | 540 | let _ = fmap (const ()) result :: Either QueryFailure () |
512 | return $ either (const (False,Nothing)) (\(_,mip)->(True,mip)) result | 541 | return $ either (const (False,Nothing)) (\(_,mip)->(True,mip)) result |
@@ -549,7 +578,7 @@ refreshNodes nid = do | |||
549 | $(logWarnS) "refreshNodes" $ "received " <> T.pack (show (L.length ns)) <> " nodes." | 578 | $(logWarnS) "refreshNodes" $ "received " <> T.pack (show (L.length ns)) <> " nodes." |
550 | _ <- queryParallel $ flip L.map ns $ \n -> do | 579 | _ <- queryParallel $ flip L.map ns $ \n -> do |
551 | $(logWarnS) "refreshNodes" $ "received node: " <> T.pack (show (pPrint n)) | 580 | $(logWarnS) "refreshNodes" $ "received node: " <> T.pack (show (pPrint n)) |
552 | pingQ (nodeAddr n) | 581 | pingQ n |
553 | -- pingQ takes care of inserting the node. | 582 | -- pingQ takes care of inserting the node. |
554 | return () | 583 | return () |
555 | return () -- \$ L.concat nss | 584 | return () -- \$ L.concat nss |
@@ -622,7 +651,7 @@ insertNode1 = do | |||
622 | , fallbackID = nid :: NodeId dht | 651 | , fallbackID = nid :: NodeId dht |
623 | , adjustID = dhtAdjustID Proxy (DHT.fallbackID params) :: SockAddr -> Event dht ip u -> NodeId dht | 652 | , adjustID = dhtAdjustID Proxy (DHT.fallbackID params) :: SockAddr -> Event dht ip u -> NodeId dht |
624 | , logMessage = logm :: Char -> String -> IO () | 653 | , logMessage = logm :: Char -> String -> IO () |
625 | , pingProbe = probe :: NodeAddr ip -> IO (Bool, Maybe ReflectedIP) | 654 | , pingProbe = probe :: NodeInfo dht ip u -> IO (Bool, Maybe ReflectedIP) |
626 | } | 655 | } |
627 | tbl <- asks routingInfo | 656 | tbl <- asks routingInfo |
628 | let state = DHT.TableKeeper | 657 | let state = DHT.TableKeeper |
@@ -651,7 +680,7 @@ queryNode :: forall raw dht u a b ip. | |||
651 | , Show (QueryMethod dht) | 680 | , Show (QueryMethod dht) |
652 | , SerializableTo raw (Response dht (Ping dht)) | 681 | , SerializableTo raw (Response dht (Ping dht)) |
653 | , SerializableTo raw (Query dht (Ping dht)) | 682 | , SerializableTo raw (Query dht (Ping dht)) |
654 | ) => NodeAddr ip -> a -> DHT raw dht u ip (NodeId dht, b) | 683 | ) => NodeInfo dht ip u -> a -> DHT raw dht u ip (NodeId dht, b) |
655 | queryNode addr q = fmap (\(n,b,_) -> (n,b)) $ queryNode' addr q | 684 | queryNode addr q = fmap (\(n,b,_) -> (n,b)) $ queryNode' addr q |
656 | 685 | ||
657 | queryNode' :: forall raw dht u a b ip. | 686 | queryNode' :: forall raw dht u a b ip. |
@@ -672,15 +701,39 @@ queryNode' :: forall raw dht u a b ip. | |||
672 | , Show (QueryMethod dht) | 701 | , Show (QueryMethod dht) |
673 | , SerializableTo raw (Response dht (Ping dht)) | 702 | , SerializableTo raw (Response dht (Ping dht)) |
674 | , SerializableTo raw (Query dht (Ping dht)) | 703 | , SerializableTo raw (Query dht (Ping dht)) |
675 | ) => NodeAddr ip -> a -> DHT raw dht u ip (NodeId dht, b, Maybe ReflectedIP) | 704 | ) => NodeInfo dht ip u -> a -> DHT raw dht u ip (NodeId dht, b, Maybe ReflectedIP) |
676 | queryNode' addr q = do | 705 | queryNode' ni q = do |
677 | nid <- myNodeIdAccordingTo addr | 706 | let addr = nodeAddr ni |
707 | dest = makeAddress (Left $ nodeId ni) (toSockAddr addr) | ||
708 | coldQueryNode' addr dest q | ||
709 | |||
710 | coldQueryNode' :: forall raw dht u a b ip. | ||
711 | ( Address ip | ||
712 | , Default u | ||
713 | , Show u | ||
714 | , DHT.Kademlia dht | ||
715 | , KRPC dht (Query dht a) (Response dht b) | ||
716 | , KRPC dht (Query dht (Ping dht)) (Response dht (Ping dht)) | ||
717 | , Ord (TransactionID dht) | ||
718 | , Serialize (TransactionID dht) | ||
719 | , WireFormat raw dht | ||
720 | , SerializableTo raw (Response dht b) | ||
721 | , SerializableTo raw (Query dht a) | ||
722 | , Ord (NodeId dht) | ||
723 | , FiniteBits (NodeId dht) | ||
724 | , Show (NodeId dht) | ||
725 | , Show (QueryMethod dht) | ||
726 | , SerializableTo raw (Response dht (Ping dht)) | ||
727 | , SerializableTo raw (Query dht (Ping dht)) | ||
728 | ) => NodeAddr ip -> PacketDestination dht -> a -> DHT raw dht u ip (NodeId dht, b, Maybe ReflectedIP) | ||
729 | coldQueryNode' addr dest q = do | ||
730 | nid <- myNodeIdAccordingTo $ fromMaybe (error "TODO: coldQueryNode' myNodeIdAccordingTo") $ fromAddr dest | ||
678 | dta <- asks dhtData | 731 | dta <- asks dhtData |
679 | qextra <- liftIO $ makeQueryExtra dta nid (Proxy :: Proxy (Query dht q)) (Proxy :: Proxy (Response dht b)) | 732 | qextra <- liftIO $ makeQueryExtra dta nid (Proxy :: Proxy (Query dht q)) (Proxy :: Proxy (Response dht b)) |
680 | let read_only = False -- TODO: check for NAT issues. (BEP 43) | 733 | let read_only = False -- TODO: check for NAT issues. (BEP 43) |
681 | -- let KRPC.Method name = KRPC.method :: KRPC.Method dht (Query dht a) (Response dht b) | 734 | -- let KRPC.Method name = KRPC.method :: KRPC.Method dht (Query dht a) (Response dht b) |
682 | mgr <- asks manager | 735 | mgr <- asks manager |
683 | (Response rextra r, remoteId, witnessed_ip) <- liftIO $ query' mgr (toSockAddr addr) (Query qextra q) | 736 | (Response rextra r, remoteId, witnessed_ip) <- liftIO $ query' mgr dest (Query qextra q) |
684 | -- \$(logDebugS) "queryNode" $ "Witnessed address: " <> T.pack (show witnessed_ip) | 737 | -- \$(logDebugS) "queryNode" $ "Witnessed address: " <> T.pack (show witnessed_ip) |
685 | -- <> " by " <> T.pack (show (toSockAddr addr)) | 738 | -- <> " by " <> T.pack (show (toSockAddr addr)) |
686 | _ <- insertNode (NodeInfo remoteId addr def) witnessed_ip | 739 | _ <- insertNode (NodeInfo remoteId addr def) witnessed_ip |
@@ -704,6 +757,6 @@ queryNode' addr q = do | |||
704 | , SerializableTo raw (Query dht (Ping dht)) | 757 | , SerializableTo raw (Query dht (Ping dht)) |
705 | , WireFormat raw dht | 758 | , WireFormat raw dht |
706 | , Kademlia dht | 759 | , Kademlia dht |
707 | ) => a -> NodeAddr ip -> DHT raw dht u ip b | 760 | ) => a -> NodeInfo dht ip u -> DHT raw dht u ip b |
708 | q <@> addr = snd <$> queryNode addr q | 761 | q <@> addr = snd <$> queryNode addr q |
709 | {-# INLINE (<@>) #-} | 762 | {-# INLINE (<@>) #-} |
diff --git a/src/Network/DHT.hs b/src/Network/DHT.hs index 0dab29cd..285cf9ff 100644 --- a/src/Network/DHT.hs +++ b/src/Network/DHT.hs | |||
@@ -115,7 +115,7 @@ insertNode param@TableParameters{..} state info witnessed_ip0 = do | |||
115 | myThreadId >>= flip labelThread "DHT.insertNode.pingResults" | 115 | myThreadId >>= flip labelThread "DHT.insertNode.pingResults" |
116 | forM_ ps $ \(CheckPing ns)-> do | 116 | forM_ ps $ \(CheckPing ns)-> do |
117 | forM_ ns $ \n -> do | 117 | forM_ ns $ \n -> do |
118 | (b,mip) <- pingProbe (nodeAddr n) | 118 | (b,mip) <- pingProbe n |
119 | let alive = PingResult n b | 119 | let alive = PingResult n b |
120 | logMessage 'D' $ "PingResult "++show (nodeId n,b) | 120 | logMessage 'D' $ "PingResult "++show (nodeId n,b) |
121 | _ <- join $ atomically $ atomicInsert param state tm alive mip | 121 | _ <- join $ atomically $ atomicInsert param state tm alive mip |
diff --git a/src/Network/DHT/Types.hs b/src/Network/DHT/Types.hs index 0102a53f..47f98ebe 100644 --- a/src/Network/DHT/Types.hs +++ b/src/Network/DHT/Types.hs | |||
@@ -18,7 +18,7 @@ import GHC.Generics | |||
18 | data TableParameters msg ip u = TableParameters | 18 | data TableParameters msg ip u = TableParameters |
19 | { maxBuckets :: Int | 19 | { maxBuckets :: Int |
20 | , fallbackID :: NodeId msg | 20 | , fallbackID :: NodeId msg |
21 | , pingProbe :: NodeAddr ip -> IO (Bool, Maybe ReflectedIP) | 21 | , pingProbe :: NodeInfo msg ip u -> IO (Bool, Maybe ReflectedIP) |
22 | , logMessage :: Char -> String -> IO () | 22 | , logMessage :: Char -> String -> IO () |
23 | , adjustID :: SockAddr -> Event msg ip u -> NodeId msg | 23 | , adjustID :: SockAddr -> Event msg ip u -> NodeId msg |
24 | } | 24 | } |
diff --git a/src/Network/DatagramServer.hs b/src/Network/DatagramServer.hs index 1376748f..ca968a8c 100644 --- a/src/Network/DatagramServer.hs +++ b/src/Network/DatagramServer.hs | |||
@@ -329,7 +329,7 @@ query :: forall h a b raw msg. | |||
329 | , SerializableTo raw a | 329 | , SerializableTo raw a |
330 | , WireFormat raw msg | 330 | , WireFormat raw msg |
331 | , KRPC msg a b | 331 | , KRPC msg a b |
332 | ) => Manager raw msg -> SockAddr -> a -> IO b | 332 | ) => Manager raw msg -> PacketDestination msg -> a -> IO b |
333 | query mgr addr params = queryK mgr addr params (\_ x _ _ -> x) | 333 | query mgr addr params = queryK mgr addr params (\_ x _ _ -> x) |
334 | 334 | ||
335 | -- | Like 'query' but possibly returns your externally routable IP address. | 335 | -- | Like 'query' but possibly returns your externally routable IP address. |
@@ -340,7 +340,7 @@ query' :: forall h a b raw msg. | |||
340 | , Serialize (TransactionID msg) | 340 | , Serialize (TransactionID msg) |
341 | , SerializableTo raw a , WireFormat raw msg | 341 | , SerializableTo raw a , WireFormat raw msg |
342 | , KRPC msg a b | 342 | , KRPC msg a b |
343 | ) => Manager raw msg -> SockAddr -> a -> IO (b , NodeId msg, Maybe ReflectedIP) | 343 | ) => Manager raw msg -> PacketDestination msg -> a -> IO (b , NodeId msg, Maybe ReflectedIP) |
344 | query' mgr addr params = queryK mgr addr params (\_ b nid ip -> (b,nid,ip)) | 344 | query' mgr addr params = queryK mgr addr params (\_ b nid ip -> (b,nid,ip)) |
345 | 345 | ||
346 | -- | Enqueue a query, but give us the complete BEncoded content sent by the | 346 | -- | Enqueue a query, but give us the complete BEncoded content sent by the |
@@ -354,7 +354,7 @@ queryRaw :: forall h a b raw msg. | |||
354 | , SerializableTo raw a | 354 | , SerializableTo raw a |
355 | , WireFormat raw msg | 355 | , WireFormat raw msg |
356 | , KRPC msg a b | 356 | , KRPC msg a b |
357 | ) => Manager raw msg -> SockAddr -> a -> IO (b , raw) | 357 | ) => Manager raw msg -> PacketDestination msg -> a -> IO (b , raw) |
358 | queryRaw mgr addr params = queryK mgr addr params (\raw x _ _ -> (x,raw)) | 358 | queryRaw mgr addr params = queryK mgr addr params (\raw x _ _ -> (x,raw)) |
359 | 359 | ||
360 | queryK :: forall h a b x raw msg. | 360 | queryK :: forall h a b x raw msg. |
@@ -366,11 +366,12 @@ queryK :: forall h a b x raw msg. | |||
366 | , Serialize (TransactionID msg) | 366 | , Serialize (TransactionID msg) |
367 | , KRPC msg a b | 367 | , KRPC msg a b |
368 | ) => | 368 | ) => |
369 | Manager raw msg -> SockAddr -> a -> (raw -> b -> NodeId msg -> Maybe ReflectedIP -> x) -> IO x | 369 | Manager raw msg -> PacketDestination msg -> a -> (raw -> b -> NodeId msg -> Maybe ReflectedIP -> x) -> IO x |
370 | queryK mgr@Manager{..} addr params kont = do | 370 | queryK mgr@Manager{..} dest params kont = do |
371 | tid <- liftIO $ genTransactionId transactionCounter | 371 | tid <- liftIO $ genTransactionId transactionCounter |
372 | let Method meth = method :: Method msg a b | 372 | let addr = toSockAddr dest |
373 | let signature = querySignature meth tid addr | 373 | Method meth = method :: Method msg a b |
374 | signature = querySignature meth tid addr | ||
374 | logMsg 'D' "query.sending" signature | 375 | logMsg 'D' "query.sending" signature |
375 | 376 | ||
376 | mres <- liftIO $ do | 377 | mres <- liftIO $ do |
@@ -380,7 +381,7 @@ queryK mgr@Manager{..} addr params kont = do | |||
380 | ctx = error "TODO TOX ToxCipherContext or () for Mainline" | 381 | ctx = error "TODO TOX ToxCipherContext or () for Mainline" |
381 | q <- buildQuery cli addr meth tid params | 382 | q <- buildQuery cli addr meth tid params |
382 | let qb = encodePayload (q :: msg a) :: msg raw | 383 | let qb = encodePayload (q :: msg a) :: msg raw |
383 | qbs = encodeHeaders ctx qb | 384 | qbs = encodeHeaders ctx qb dest |
384 | sendQuery sock addr qbs | 385 | sendQuery sock addr qbs |
385 | `onException` unregisterQuery (tid, addr) pendingCalls | 386 | `onException` unregisterQuery (tid, addr) pendingCalls |
386 | 387 | ||
@@ -528,7 +529,8 @@ handleQuery mgr@Manager{..} hs meth raw q addr = void $ fork $ do | |||
528 | res <- dispatchHandler mgr hs meth q addr | 529 | res <- dispatchHandler mgr hs meth q addr |
529 | let res' = either buildError Just res | 530 | let res' = either buildError Just res |
530 | ctx = error "TODO TOX ToxCipherContext 2 or () for Mainline" | 531 | ctx = error "TODO TOX ToxCipherContext 2 or () for Mainline" |
531 | resbs = fmap (encodeHeaders ctx) res' :: Maybe BS.ByteString | 532 | dest = makeAddress (Right q) addr |
533 | resbs = fmap (\raw -> encodeHeaders ctx raw dest) res' :: Maybe BS.ByteString | ||
532 | -- TODO: Generalize this debug print. | 534 | -- TODO: Generalize this debug print. |
533 | -- resbe = either toBEncode toBEncode res | 535 | -- resbe = either toBEncode toBEncode res |
534 | -- .(logOther "q") \$ T.unlines | 536 | -- .(logOther "q") \$ T.unlines |
diff --git a/src/Network/DatagramServer/Mainline.hs b/src/Network/DatagramServer/Mainline.hs index 89a275c1..1f07b13f 100644 --- a/src/Network/DatagramServer/Mainline.hs +++ b/src/Network/DatagramServer/Mainline.hs | |||
@@ -79,6 +79,7 @@ import Data.Typeable | |||
79 | import Network.Socket (SockAddr (..),PortNumber,HostAddress) | 79 | import Network.Socket (SockAddr (..),PortNumber,HostAddress) |
80 | import Text.PrettyPrint as PP hiding ((<>)) | 80 | import Text.PrettyPrint as PP hiding ((<>)) |
81 | import Text.PrettyPrint.HughesPJClass hiding (($$), (<>)) | 81 | import Text.PrettyPrint.HughesPJClass hiding (($$), (<>)) |
82 | import Data.Hashable | ||
82 | 83 | ||
83 | 84 | ||
84 | -- | This transaction ID is generated by the querying node and is | 85 | -- | This transaction ID is generated by the querying node and is |
@@ -290,6 +291,9 @@ instance Envelope KMessageOf where | |||
290 | } | 291 | } |
291 | deriving (Show, Eq, Ord, Typeable) | 292 | deriving (Show, Eq, Ord, Typeable) |
292 | 293 | ||
294 | newtype PacketDestination KMessageOf = MainlineNode SockAddr | ||
295 | deriving (Show, Eq, Ord, Typeable) | ||
296 | |||
293 | envelopePayload (Q q) = queryArgs q | 297 | envelopePayload (Q q) = queryArgs q |
294 | envelopePayload (R r) = respVals r | 298 | envelopePayload (R r) = respVals r |
295 | envelopePayload (E _) = error "TODO: messagePayload for KError" | 299 | envelopePayload (E _) = error "TODO: messagePayload for KError" |
@@ -302,6 +306,9 @@ instance Envelope KMessageOf where | |||
302 | envelopeClass (R r) = Response (respIP r) | 306 | envelopeClass (R r) = Response (respIP r) |
303 | envelopeClass (E e) = Error e | 307 | envelopeClass (E e) = Error e |
304 | 308 | ||
309 | -- replyAddress :: envelope a -> SockAddr -> PacketDestination envelope | ||
310 | makeAddress _ addr = MainlineNode addr | ||
311 | |||
305 | buildReply self addr qry response = | 312 | buildReply self addr qry response = |
306 | (R (KResponse response (envelopeTransaction qry) (Just $ ReflectedIP addr))) | 313 | (R (KResponse response (envelopeTransaction qry) (Just $ ReflectedIP addr))) |
307 | 314 | ||
@@ -311,6 +318,20 @@ instance Envelope KMessageOf where | |||
311 | 318 | ||
312 | fromRoutableNode = not . queryIsReadOnly | 319 | fromRoutableNode = not . queryIsReadOnly |
313 | 320 | ||
321 | instance Hashable (PacketDestination KMessageOf) where | ||
322 | hashWithSalt s (MainlineNode sockaddr) = hashWithSalt s (show sockaddr) | ||
323 | |||
324 | -- Serialize, Pretty) PacketDestination KMessageOf = MainlineNode SockAddr | ||
325 | instance Serialize (PacketDestination KMessageOf) where | ||
326 | put (MainlineNode addr) = putSockAddr addr | ||
327 | get = MainlineNode <$> getSockAddr | ||
328 | |||
329 | instance Pretty (PacketDestination KMessageOf) where | ||
330 | pPrint (MainlineNode addr) = PP.text $ show addr | ||
331 | |||
332 | instance Address (PacketDestination KMessageOf) where | ||
333 | toSockAddr (MainlineNode addr) = addr | ||
334 | fromSockAddr addr = Just $ MainlineNode addr | ||
314 | 335 | ||
315 | instance WireFormat BValue KMessageOf where | 336 | instance WireFormat BValue KMessageOf where |
316 | type SerializableTo BValue = BEncode | 337 | type SerializableTo BValue = BEncode |
@@ -323,7 +344,7 @@ instance WireFormat BValue KMessageOf where | |||
323 | decodeHeaders _ = BE.fromBEncode | 344 | decodeHeaders _ = BE.fromBEncode |
324 | decodePayload kmsg = mapM BE.fromBEncode kmsg | 345 | decodePayload kmsg = mapM BE.fromBEncode kmsg |
325 | 346 | ||
326 | encodeHeaders _ kmsg = L.toStrict $ BE.encode kmsg | 347 | encodeHeaders _ kmsg _ = L.toStrict $ BE.encode kmsg |
327 | encodePayload msg = fmap BE.toBEncode msg | 348 | encodePayload msg = fmap BE.toBEncode msg |
328 | 349 | ||
329 | -- | KRPC 'compact list' compatible encoding: contact information for | 350 | -- | KRPC 'compact list' compatible encoding: contact information for |
diff --git a/src/Network/DatagramServer/Tox.hs b/src/Network/DatagramServer/Tox.hs index f666b951..8d2f9289 100644 --- a/src/Network/DatagramServer/Tox.hs +++ b/src/Network/DatagramServer/Tox.hs | |||
@@ -11,10 +11,13 @@ | |||
11 | {-# LANGUAGE TupleSections #-} | 11 | {-# LANGUAGE TupleSections #-} |
12 | {-# LANGUAGE TypeFamilies #-} | 12 | {-# LANGUAGE TypeFamilies #-} |
13 | {-# LANGUAGE UnboxedTuples #-} | 13 | {-# LANGUAGE UnboxedTuples #-} |
14 | {-# LANGUAGE TemplateHaskell #-} | ||
15 | {-# LANGUAGE RankNTypes #-} | ||
14 | module Network.DatagramServer.Tox where | 16 | module Network.DatagramServer.Tox where |
15 | 17 | ||
16 | import Data.Bits | 18 | import Data.Bits |
17 | import Data.ByteString (ByteString) | 19 | import Data.ByteString (ByteString) |
20 | import Data.ByteArray as BA (ByteArrayAccess,length,withByteArray) | ||
18 | import qualified Data.Serialize as S | 21 | import qualified Data.Serialize as S |
19 | -- import qualified Data.ByteString.Lazy as L | 22 | -- import qualified Data.ByteString.Lazy as L |
20 | import qualified Data.ByteString.Char8 as Char8 | 23 | import qualified Data.ByteString.Char8 as Char8 |
@@ -23,12 +26,25 @@ import Data.Word | |||
23 | import Data.LargeWord | 26 | import Data.LargeWord |
24 | import Data.IP | 27 | import Data.IP |
25 | import Data.Serialize | 28 | import Data.Serialize |
26 | -- import Network.Address (NodeInfo(..)) -- Serialize IP | 29 | import Network.Address |
27 | import GHC.Generics (Generic) | 30 | import GHC.Generics (Generic) |
28 | import Network.Socket | 31 | import Network.Socket |
29 | import Network.DatagramServer.Types | 32 | import Network.DatagramServer.Types |
30 | import qualified Network.DatagramServer.Types as Envelope (NodeId) | 33 | import qualified Network.DatagramServer.Types as Envelope (NodeId) |
31 | import Crypto.PubKey.ECC.Types | 34 | import Crypto.PubKey.ECC.Types |
35 | import Crypto.PubKey.Curve25519 | ||
36 | import Crypto.ECC.Class | ||
37 | import qualified Crypto.Cipher.XSalsa as Salsa20 | ||
38 | import Data.LargeWord | ||
39 | import Foreign.Ptr | ||
40 | import Foreign.Storable | ||
41 | import Foreign.Marshal.Alloc | ||
42 | import Data.Typeable | ||
43 | import StaticAssert | ||
44 | import Crypto.Error.Types | ||
45 | import Data.Hashable | ||
46 | import Text.PrettyPrint as PP hiding ((<>)) | ||
47 | import Text.PrettyPrint.HughesPJClass hiding (($$), (<>)) | ||
32 | 48 | ||
33 | 49 | ||
34 | type Key32 = Word256 -- 32 byte key | 50 | type Key32 = Word256 -- 32 byte key |
@@ -203,7 +219,9 @@ instance Serialize NodeFormat where | |||
203 | -- [Sendback data, length=8 bytes] | 219 | -- [Sendback data, length=8 bytes] |
204 | -- ] | 220 | -- ] |
205 | 221 | ||
206 | data ToxCipherContext = ToxCipherContext -- TODO | 222 | data ToxCipherContext = ToxCipherContext |
223 | { dhtSecretKey :: SecretKey | ||
224 | } | ||
207 | 225 | ||
208 | newtype Ciphered = Ciphered { cipheredBytes :: ByteString } | 226 | newtype Ciphered = Ciphered { cipheredBytes :: ByteString } |
209 | 227 | ||
@@ -227,29 +245,51 @@ putMessage (Message {..}) = do | |||
227 | let Ciphered bs = msgPayload | 245 | let Ciphered bs = msgPayload |
228 | putByteString bs | 246 | putByteString bs |
229 | 247 | ||
248 | id2key :: NodeId Message -> PublicKey | ||
249 | id2key recipient = case publicKey recipient of | ||
250 | CryptoPassed key -> key | ||
251 | CryptoFailed e -> error ("id2key: "++show e) | ||
252 | |||
253 | lookupSecret :: ToxCipherContext -> NodeId Message -> TransactionID Message -> Salsa20.State | ||
254 | lookupSecret ctx recipient nonce = Salsa20.initialize 20 key nonce | ||
255 | where | ||
256 | key = ecdh (Proxy :: Proxy Curve_X25519) (dhtSecretKey ctx) (id2key recipient) -- ByteArrayAccess b => b | ||
257 | |||
230 | decipher :: ToxCipherContext -> Message Ciphered -> Either String (Message ByteString) | 258 | decipher :: ToxCipherContext -> Message Ciphered -> Either String (Message ByteString) |
231 | decipher = error "TODO TOX: decipher" | 259 | decipher ctx ciphered = Right (fst . Salsa20.combine st . cipheredBytes <$> ciphered) |
260 | where | ||
261 | st = lookupSecret ctx (msgClient ciphered) (msgNonce ciphered) | ||
232 | 262 | ||
233 | encipher :: ToxCipherContext -> Message ByteString -> Message Ciphered | 263 | encipher :: ToxCipherContext -> NodeId Message -> Message ByteString -> Message Ciphered |
234 | encipher = error "TODO TOX: encipher" | 264 | encipher ctx recipient plain = Ciphered . fst . Salsa20.combine st <$> plain |
265 | where | ||
266 | st = lookupSecret ctx recipient (msgNonce plain) | ||
235 | 267 | ||
236 | -- see rfc7748 | 268 | -- see rfc7748 |
269 | -- | ||
270 | -- Crypto.ECC | ||
271 | -- Crypto.PubKey.Curve25519 | ||
272 | -- Crypto.Cipher.XSalsa | ||
273 | -- | ||
237 | curve25519 :: Curve | 274 | curve25519 :: Curve |
238 | curve25519 = CurveFP (CurvePrime prime curvecommon) | 275 | curve25519 = CurveFP (CurvePrime prime curvecommon) |
239 | where | 276 | where |
240 | prime = 2^255 - 19 -- (≅ 1 modulo 4) | 277 | prime = 2^255 - 19 -- (≅ 1 modulo 4) |
241 | 278 | ||
279 | sqrt_of_39420360 = 14781619447589544791020593568409986887264606134616475288964881837755586237401 | ||
280 | |||
242 | -- 1 * v^2 = u^3 + 486662*u^2 + u | 281 | -- 1 * v^2 = u^3 + 486662*u^2 + u |
243 | 282 | ||
244 | curvecommon = CurveCommon | 283 | curvecommon = CurveCommon |
245 | { ecc_a = 486662 | 284 | { ecc_a = 486662 |
246 | , ecc_b = 1 | 285 | , ecc_b = 1 |
247 | , ecc_g = Point 9 14781619447589544791020593568409986887264606134616475288964881837755586237401 -- base point | 286 | , ecc_g = Point 9 sqrt_of_39420360 -- base point |
248 | , ecc_n = 2^252 + 0x14def9dea2f79cd65812631a5cf5d3ed -- order | 287 | , ecc_n = 2^252 + 0x14def9dea2f79cd65812631a5cf5d3ed -- order |
249 | , ecc_h = 8 -- cofactor | 288 | , ecc_h = 8 -- cofactor |
250 | } | 289 | } |
251 | 290 | ||
252 | 291 | -- crypto_box uses xsalsa20 symmetric encryption and poly1305 authentication. | |
292 | -- https://en.wikipedia.org/wiki/Poly1305 | ||
253 | 293 | ||
254 | instance Envelope Message where | 294 | instance Envelope Message where |
255 | newtype TransactionID Message = TID Nonce24 | 295 | newtype TransactionID Message = TID Nonce24 |
@@ -263,6 +303,11 @@ instance Envelope Message where | |||
263 | newtype QueryExtra Message = QueryNonce { qryNonce :: Nonce8 } | 303 | newtype QueryExtra Message = QueryNonce { qryNonce :: Nonce8 } |
264 | newtype ResponseExtra Message = ResponseNonce { rspNonce :: Nonce8 } | 304 | newtype ResponseExtra Message = ResponseNonce { rspNonce :: Nonce8 } |
265 | 305 | ||
306 | data PacketDestination Message = ToxAddr { toxID :: NodeId Message | ||
307 | , toxSockAddr :: SockAddr | ||
308 | } | ||
309 | deriving (Eq,Ord,Show) | ||
310 | |||
266 | envelopePayload = msgPayload | 311 | envelopePayload = msgPayload |
267 | 312 | ||
268 | envelopeTransaction = msgNonce | 313 | envelopeTransaction = msgNonce |
@@ -272,15 +317,70 @@ instance Envelope Message where | |||
272 | envelopeClass Message { msgType = GetNodes } = Query GetNodes | 317 | envelopeClass Message { msgType = GetNodes } = Query GetNodes |
273 | envelopeClass Message { msgType = SendNodes } = Response Nothing | 318 | envelopeClass Message { msgType = SendNodes } = Response Nothing |
274 | 319 | ||
320 | makeAddress qry = ToxAddr (either id msgClient qry) | ||
321 | |||
275 | buildReply self addr qry payload = (fmap (const payload) qry) { msgClient = self } | 322 | buildReply self addr qry payload = (fmap (const payload) qry) { msgClient = self } |
276 | 323 | ||
277 | -- buildQuery :: NodeId envelope -> SockAddr -> QueryMethod envelope -> TransactionID envelope -> a -> IO (envelope a) | 324 | -- buildQuery :: NodeId envelope -> SockAddr -> QueryMethod envelope -> TransactionID envelope -> a -> IO (envelope a) |
278 | -- buildQuery nid addr meth tid q = todo | 325 | buildQuery nid addr meth tid q = return $ Message |
326 | { msgType = meth | ||
327 | , msgClient = nid | ||
328 | , msgNonce = tid | ||
329 | , msgPayload = q | ||
330 | } | ||
279 | 331 | ||
280 | uniqueTransactionId cnt = do | 332 | uniqueTransactionId cnt = do |
281 | return $ either (error "failed to create TransactionId") TID | 333 | return $ either (error "failed to create TransactionId") TID |
282 | $ S.decode $ Char8.pack (take 24 $ show cnt ++ repeat ' ') | 334 | $ S.decode $ Char8.pack (take 24 $ show cnt ++ repeat ' ') |
283 | 335 | ||
336 | |||
337 | staticAssert isLittleEndian -- assumed by 'withWord64Ptr' | ||
338 | |||
339 | with3Word64Ptr :: Nonce24 -> (Ptr Word64 -> IO a) -> IO a | ||
340 | with3Word64Ptr (LargeKey wlo (LargeKey wmid whi)) kont = | ||
341 | allocaBytes (sizeOf wlo * 3) $ \p -> do | ||
342 | pokeElemOff p 0 wlo | ||
343 | pokeElemOff p 1 wmid | ||
344 | pokeElemOff p 2 whi | ||
345 | kont p | ||
346 | |||
347 | with4Word64Ptr :: Key32 -> (Ptr Word64 -> IO a) -> IO a | ||
348 | with4Word64Ptr (LargeKey wlo (LargeKey wmid (LargeKey whi whighest))) kont = | ||
349 | allocaBytes (sizeOf wlo * 4) $ \p -> do | ||
350 | pokeElemOff p 0 wlo | ||
351 | pokeElemOff p 1 wmid | ||
352 | pokeElemOff p 2 whi | ||
353 | pokeElemOff p 3 whighest | ||
354 | kont p | ||
355 | |||
356 | |||
357 | instance ByteArrayAccess (TransactionID Message) where | ||
358 | length _ = 24 | ||
359 | withByteArray (TID nonce) kont = with3Word64Ptr nonce (kont . castPtr) | ||
360 | |||
361 | instance ByteArrayAccess (NodeId Message) where | ||
362 | length _ = 32 | ||
363 | withByteArray (NodeId nonce) kont = with4Word64Ptr nonce (kont . castPtr) | ||
364 | |||
365 | |||
366 | instance Hashable (NodeId Message) where | ||
367 | hashWithSalt s (NodeId (LargeKey a (LargeKey b (LargeKey c d)))) = | ||
368 | hashWithSalt s (a,b,c,d) | ||
369 | |||
370 | instance Hashable (PacketDestination Message) where | ||
371 | hashWithSalt s (ToxAddr nid addr) = hashWithSalt s nid | ||
372 | |||
373 | instance Serialize (PacketDestination Message) where | ||
374 | put (ToxAddr (NodeId nid) addr) = put nid >> putSockAddr addr | ||
375 | get = ToxAddr <$> (NodeId <$> get) <*> getSockAddr | ||
376 | |||
377 | instance Pretty (PacketDestination Message) where | ||
378 | pPrint = PP.text . show | ||
379 | |||
380 | instance Address (PacketDestination Message) where | ||
381 | toSockAddr (ToxAddr _ addr) = addr | ||
382 | fromSockAddr _ = Nothing | ||
383 | |||
284 | instance WireFormat ByteString Message where | 384 | instance WireFormat ByteString Message where |
285 | type SerializableTo ByteString = Serialize | 385 | type SerializableTo ByteString = Serialize |
286 | type CipherContext ByteString Message = ToxCipherContext | 386 | type CipherContext ByteString Message = ToxCipherContext |
@@ -289,6 +389,6 @@ instance WireFormat ByteString Message where | |||
289 | encodePayload = fmap encode | 389 | encodePayload = fmap encode |
290 | 390 | ||
291 | decodeHeaders ctx bs = runGet getMessage bs >>= decipher ctx | 391 | decodeHeaders ctx bs = runGet getMessage bs >>= decipher ctx |
292 | encodeHeaders ctx msg = runPut $ putMessage $ encipher ctx msg | 392 | encodeHeaders ctx msg recipient = runPut $ putMessage $ encipher ctx (toxID recipient) msg |
293 | 393 | ||
294 | instance Read (NodeId Message) where readsPrec d s = map (\(w,xs) -> (NodeId w, xs)) $ decodeHex s | 394 | instance Read (NodeId Message) where readsPrec d s = map (\(w,xs) -> (NodeId w, xs)) $ decodeHex s |
diff --git a/src/Network/DatagramServer/Types.hs b/src/Network/DatagramServer/Types.hs index 13f79afb..14968764 100644 --- a/src/Network/DatagramServer/Types.hs +++ b/src/Network/DatagramServer/Types.hs | |||
@@ -96,11 +96,21 @@ class Envelope envelope where | |||
96 | data NodeId envelope | 96 | data NodeId envelope |
97 | data QueryExtra envelope | 97 | data QueryExtra envelope |
98 | data ResponseExtra envelope | 98 | data ResponseExtra envelope |
99 | data PacketDestination envelope | ||
99 | 100 | ||
100 | envelopePayload :: envelope a -> a | 101 | envelopePayload :: envelope a -> a |
101 | envelopeTransaction :: envelope a -> TransactionID envelope | 102 | envelopeTransaction :: envelope a -> TransactionID envelope |
102 | envelopeClass :: envelope a -> MessageClass envelope | 103 | envelopeClass :: envelope a -> MessageClass envelope |
103 | 104 | ||
105 | -- | > replyAddress qry addr | ||
106 | -- | ||
107 | -- [ qry ] received query message | ||
108 | -- | ||
109 | -- [ addr ] SockAddr of query origin | ||
110 | -- | ||
111 | -- Returns: Destination address for reply. | ||
112 | makeAddress :: Either (NodeId envelope) (envelope a) -> SockAddr -> PacketDestination envelope | ||
113 | |||
104 | -- | > buildReply self addr qry response | 114 | -- | > buildReply self addr qry response |
105 | -- | 115 | -- |
106 | -- [ self ] this node's id. | 116 | -- [ self ] this node's id. |
@@ -320,8 +330,7 @@ genBucketSample' gen self (q,m,b) | |||
320 | h = xor b (complement m .&. BS.last hd) | 330 | h = xor b (complement m .&. BS.last hd) |
321 | t = m .&. BS.head tl | 331 | t = m .&. BS.head tl |
322 | 332 | ||
323 | 333 | class (Envelope envelope, Address (PacketDestination envelope)) => WireFormat raw envelope where | |
324 | class Envelope envelope => WireFormat raw envelope where | ||
325 | type SerializableTo raw :: * -> Constraint | 334 | type SerializableTo raw :: * -> Constraint |
326 | type CipherContext raw envelope | 335 | type CipherContext raw envelope |
327 | 336 | ||
@@ -336,7 +345,7 @@ class Envelope envelope => WireFormat raw envelope where | |||
336 | decodeHeaders :: CipherContext raw envelope -> raw -> Either String (envelope raw) | 345 | decodeHeaders :: CipherContext raw envelope -> raw -> Either String (envelope raw) |
337 | decodePayload :: SerializableTo raw a => envelope raw -> Either String (envelope a) | 346 | decodePayload :: SerializableTo raw a => envelope raw -> Either String (envelope a) |
338 | 347 | ||
339 | encodeHeaders :: CipherContext raw envelope -> envelope raw -> ByteString | 348 | encodeHeaders :: CipherContext raw envelope -> envelope raw -> PacketDestination envelope -> ByteString |
340 | encodePayload :: SerializableTo raw a => envelope a -> envelope raw | 349 | encodePayload :: SerializableTo raw a => envelope a -> envelope raw |
341 | 350 | ||
342 | encodeHexDoc :: Serialize x => x -> Doc | 351 | encodeHexDoc :: Serialize x => x -> Doc |
@@ -359,3 +368,21 @@ instance (Pretty ip, Pretty (NodeId dht)) => Pretty [NodeInfo dht ip u] where | |||
359 | pPrint = PP.vcat . PP.punctuate "," . map pPrint | 368 | pPrint = PP.vcat . PP.punctuate "," . map pPrint |
360 | 369 | ||
361 | 370 | ||
371 | |||
372 | putSockAddr (SockAddrInet port addr) | ||
373 | = put (0x34 :: Word8) >> put port >> put addr | ||
374 | putSockAddr (SockAddrInet6 port flow addr scope) | ||
375 | = put (0x36 :: Word8) >> put port >> put addr >> put scope >> put flow | ||
376 | putSockAddr (SockAddrUnix path) | ||
377 | = put (0x75 :: Word8) >> put path | ||
378 | putSockAddr (SockAddrCan num) | ||
379 | = put (0x63 :: Word8) >> put num | ||
380 | |||
381 | getSockAddr = do | ||
382 | c <- get | ||
383 | case c :: Word8 of | ||
384 | 0x34 -> SockAddrInet <$> get <*> get | ||
385 | 0x36 -> (\p a s f -> SockAddrInet6 p f a s) <$> get <*> get <*> get <*> get | ||
386 | 0x75 -> SockAddrUnix <$> get | ||
387 | 0x63 -> SockAddrCan <$> get | ||
388 | _ -> fail "getSockAddr" | ||