diff options
author | joe <joe@jerkface.net> | 2017-07-25 22:10:22 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-07-25 22:10:22 -0400 |
commit | 66e9813be8b61e57f7cf61bb4b21dc90f3e79d30 (patch) | |
tree | b45fe067877e45c5f6f16c441e17c14406800d77 /Mainline.hs | |
parent | 480088a97f9622b7bb56978f3596e87ee7c770a0 (diff) |
Bootstrap fixes.
Diffstat (limited to 'Mainline.hs')
-rw-r--r-- | Mainline.hs | 68 |
1 files changed, 59 insertions, 9 deletions
diff --git a/Mainline.hs b/Mainline.hs index 911f0dbc..b24f847d 100644 --- a/Mainline.hs +++ b/Mainline.hs | |||
@@ -73,6 +73,9 @@ import Control.Concurrent.Lifted | |||
73 | import GHC.Conc (labelThread) | 73 | import GHC.Conc (labelThread) |
74 | #endif | 74 | #endif |
75 | import Control.Exception (SomeException(..),handle) | 75 | import Control.Exception (SomeException(..),handle) |
76 | import Data.Aeson (FromJSON,ToJSON,(.=)) | ||
77 | import qualified Data.Aeson as JSON | ||
78 | import Text.Read | ||
76 | 79 | ||
77 | newtype NodeId = NodeId ByteString | 80 | newtype NodeId = NodeId ByteString |
78 | deriving (Eq,Ord,ByteArrayAccess, BEncode, Bits, Hashable) | 81 | deriving (Eq,Ord,ByteArrayAccess, BEncode, Bits, Hashable) |
@@ -97,6 +100,36 @@ data NodeInfo = NodeInfo | |||
97 | } | 100 | } |
98 | deriving (Eq,Ord) | 101 | deriving (Eq,Ord) |
99 | 102 | ||
103 | instance ToJSON NodeInfo where | ||
104 | toJSON (NodeInfo nid (IPv4 ip) port) | ||
105 | = JSON.object [ "node-id" .= show nid | ||
106 | , "ipv4" .= show ip | ||
107 | , "port" .= (fromIntegral port :: Int) | ||
108 | ] | ||
109 | toJSON (NodeInfo nid (IPv6 ip6) port) | ||
110 | | Just ip <- un4map ip6 | ||
111 | = JSON.object [ "node-id" .= show nid | ||
112 | , "ipv4" .= show ip | ||
113 | , "port" .= (fromIntegral port :: Int) | ||
114 | ] | ||
115 | | otherwise | ||
116 | = JSON.object [ "node-id" .= show nid | ||
117 | , "ipv6" .= show ip6 | ||
118 | , "port" .= (fromIntegral port :: Int) | ||
119 | ] | ||
120 | instance FromJSON NodeInfo where | ||
121 | parseJSON (JSON.Object v) = do | ||
122 | nidstr <- v JSON..: "node-id" | ||
123 | ip6str <- v JSON..:? "ipv6" | ||
124 | ip4str <- v JSON..:? "ipv4" | ||
125 | portnum <- v JSON..: "port" | ||
126 | ip <- maybe empty (return . IPv6) (ip6str >>= readMaybe) | ||
127 | <|> maybe empty (return . IPv4) (ip4str >>= readMaybe) | ||
128 | let (bs,_) = Base16.decode (Char8.pack nidstr) | ||
129 | guard (B.length bs == 20) | ||
130 | return $ NodeInfo (NodeId bs) ip (fromIntegral (portnum :: Word16)) | ||
131 | |||
132 | |||
100 | -- The Hashable instance depends only on the IP address and port number. It is | 133 | -- The Hashable instance depends only on the IP address and port number. It is |
101 | -- used to compute the announce token. | 134 | -- used to compute the announce token. |
102 | instance Hashable NodeInfo where | 135 | instance Hashable NodeInfo where |
@@ -145,11 +178,14 @@ putNodeInfo6 (NodeInfo (NodeId nid) (IPv6 ip) port) | |||
145 | putNodeInfo6 _ = return () | 178 | putNodeInfo6 _ = return () |
146 | 179 | ||
147 | 180 | ||
148 | -- TODO: We should use a SocketAddrInet6 address for a dual-stack listen | 181 | -- | TODO: This should depend on the bind address to support IPv4-only. For |
149 | -- socket. Therefore, the behavior of this method should depend on the bind | 182 | -- now, in order to support dual-stack listen, we're going to assume IPv6 is |
150 | -- address for outbound packets. | 183 | -- wanted and map IPv4 addresses accordingly. |
151 | nodeAddr :: NodeInfo -> SockAddr | 184 | nodeAddr :: NodeInfo -> SockAddr |
152 | nodeAddr (NodeInfo _ ip port) = setPort port $ toSockAddr ip | 185 | nodeAddr (NodeInfo _ ip port) = |
186 | case ip of | ||
187 | IPv4 ip4 -> setPort port $ toSockAddr (ipv4ToIPv6 ip4) | ||
188 | IPv6 ip6 -> setPort port $ toSockAddr ip6 | ||
153 | 189 | ||
154 | nodeInfo :: NodeId -> SockAddr -> Either String NodeInfo | 190 | nodeInfo :: NodeId -> SockAddr -> Either String NodeInfo |
155 | nodeInfo nid saddr | 191 | nodeInfo nid saddr |
@@ -503,6 +539,16 @@ newClient addr = do | |||
503 | 539 | ||
504 | -- | Modifies a purely random 'NodeId' to one that is related to a given | 540 | -- | Modifies a purely random 'NodeId' to one that is related to a given |
505 | -- routable address in accordance with BEP 42. | 541 | -- routable address in accordance with BEP 42. |
542 | -- | ||
543 | -- Test vectors from the spec: | ||
544 | -- | ||
545 | -- IP rand example node ID | ||
546 | -- ============ ===== ========================================== | ||
547 | -- 124.31.75.21 1 5fbfbf f10c5d6a4ec8a88e4c6ab4c28b95eee4 01 | ||
548 | -- 21.75.31.124 86 5a3ce9 c14e7a08645677bbd1cfe7d8f956d532 56 | ||
549 | -- 65.23.51.170 22 a5d432 20bc8f112a3d426c84764f8c2a1150e6 16 | ||
550 | -- 84.124.73.14 65 1b0321 dd1bb1fe518101ceef99462b947a01ff 41 | ||
551 | -- 43.213.53.83 90 e56f6c bf5b7c4be0237986d5243b87aa6d5130 5a | ||
506 | bep42 :: SockAddr -> NodeId -> Maybe NodeId | 552 | bep42 :: SockAddr -> NodeId -> Maybe NodeId |
507 | bep42 addr (NodeId r) | 553 | bep42 addr (NodeId r) |
508 | | Just ip <- fmap S.encode (fromSockAddr addr :: Maybe IPv4) | 554 | | Just ip <- fmap S.encode (fromSockAddr addr :: Maybe IPv4) |
@@ -513,10 +559,9 @@ bep42 addr (NodeId r) | |||
513 | where | 559 | where |
514 | ip4mask = "\x03\x0f\x3f\xff" :: ByteString | 560 | ip4mask = "\x03\x0f\x3f\xff" :: ByteString |
515 | ip6mask = "\x01\x03\x07\x0f\x1f\x3f\x7f\xff" :: ByteString | 561 | ip6mask = "\x01\x03\x07\x0f\x1f\x3f\x7f\xff" :: ByteString |
516 | nbhood_select = (B.last r :: Word8) .&. 7 | 562 | nbhood_select = B.last r .&. 7 |
517 | nodeIdSize = 20 | 563 | retr n = pure $ B.drop (B.length r - n) r |
518 | retr n = pure $ B.drop (nodeIdSize - n) $ S.encode r | 564 | crc = S.encode . crc32c . B.pack |
519 | crc = (`B.append` B.replicate 16 0) . S.encode . crc32c . B.pack | ||
520 | applyMask ip = case B.zipWith (.&.) msk ip of | 565 | applyMask ip = case B.zipWith (.&.) msk ip of |
521 | (b:bs) -> (b .|. shiftL nbhood_select 5) : bs | 566 | (b:bs) -> (b .|. shiftL nbhood_select 5) : bs |
522 | bs -> bs | 567 | bs -> bs |
@@ -524,6 +569,7 @@ bep42 addr (NodeId r) | |||
524 | | otherwise = ip6mask | 569 | | otherwise = ip6mask |
525 | 570 | ||
526 | 571 | ||
572 | |||
527 | defaultHandler :: ByteString -> Handler | 573 | defaultHandler :: ByteString -> Handler |
528 | defaultHandler meth = MethodHandler decodePayload errorPayload returnError | 574 | defaultHandler meth = MethodHandler decodePayload errorPayload returnError |
529 | where | 575 | where |
@@ -540,7 +586,11 @@ mainlineKademlia client committee var sched | |||
540 | io2 <- touchBucket mainlineSpace (15*60) var sched tr | 586 | io2 <- touchBucket mainlineSpace (15*60) var sched tr |
541 | return $ do | 587 | return $ do |
542 | io1 >> io2 | 588 | io1 >> io2 |
543 | hPutStrLn stderr ("Buckets: "++show tr) | 589 | hPutStrLn stderr $ unwords |
590 | [ "Buckets: " | ||
591 | , show (transitionedTo tr) | ||
592 | , show (transitioningNode tr) | ||
593 | ] | ||
544 | } | 594 | } |
545 | 595 | ||
546 | 596 | ||