diff options
-rw-r--r-- | OnionRouter.hs | 50 | ||||
-rw-r--r-- | Presence/Presence.hs | 2 | ||||
-rw-r--r-- | examples/dhtd.hs | 32 | ||||
-rw-r--r-- | src/Network/BitTorrent/MainlineDHT.hs | 10 | ||||
-rw-r--r-- | src/Network/Kademlia.hs | 6 | ||||
-rw-r--r-- | src/Network/Kademlia/Bootstrap.hs | 6 | ||||
-rw-r--r-- | src/Network/Tox.hs | 5 | ||||
-rw-r--r-- | src/Network/Tox/DHT/Handlers.hs | 34 | ||||
-rw-r--r-- | src/Network/Tox/NodeId.hs | 2 |
9 files changed, 115 insertions, 32 deletions
diff --git a/OnionRouter.hs b/OnionRouter.hs index ad6323fe..0e0b5afb 100644 --- a/OnionRouter.hs +++ b/OnionRouter.hs | |||
@@ -6,10 +6,12 @@ import Control.Concurrent.Lifted.Instrument | |||
6 | import Crypto.Tox | 6 | import Crypto.Tox |
7 | import Network.Address | 7 | import Network.Address |
8 | import Network.Kademlia | 8 | import Network.Kademlia |
9 | import Network.Kademlia.Routing | 9 | import Network.Kademlia.Bootstrap |
10 | import Network.Kademlia.Routing as R | ||
10 | import Network.QueryResponse | 11 | import Network.QueryResponse |
11 | import Network.Tox.NodeId | 12 | import Network.Tox.NodeId |
12 | import Network.Tox.Onion.Transport | 13 | import Network.Tox.Onion.Transport |
14 | import qualified Network.Tox.TCP as TCP | ||
13 | 15 | ||
14 | import Control.Concurrent.STM | 16 | import Control.Concurrent.STM |
15 | import Control.Concurrent.STM.TArray | 17 | import Control.Concurrent.STM.TArray |
@@ -20,11 +22,13 @@ import Data.Bits | |||
20 | import Data.Bool | 22 | import Data.Bool |
21 | import Data.List | 23 | import Data.List |
22 | import qualified Data.ByteString as B | 24 | import qualified Data.ByteString as B |
25 | import Data.Hashable | ||
23 | import qualified Data.HashMap.Strict as HashMap | 26 | import qualified Data.HashMap.Strict as HashMap |
24 | ;import Data.HashMap.Strict (HashMap) | 27 | ;import Data.HashMap.Strict (HashMap) |
25 | import qualified Data.IntMap as IntMap | 28 | import qualified Data.IntMap as IntMap |
26 | ;import Data.IntMap (IntMap) | 29 | ;import Data.IntMap (IntMap) |
27 | import Data.Maybe | 30 | import Data.Maybe |
31 | import Data.Ord | ||
28 | import qualified Data.Serialize as S | 32 | import qualified Data.Serialize as S |
29 | import Data.Time.Clock.POSIX | 33 | import Data.Time.Clock.POSIX |
30 | import Data.Typeable | 34 | import Data.Typeable |
@@ -75,6 +79,12 @@ data OnionRouter = OnionRouter | |||
75 | -- than the 'routeVersion' set in 'routeMap' when the route should be | 79 | -- than the 'routeVersion' set in 'routeMap' when the route should be |
76 | -- discarded and replaced with a fresh one. | 80 | -- discarded and replaced with a fresh one. |
77 | , pendingRoutes :: TArray Int Int | 81 | , pendingRoutes :: TArray Int Int |
82 | -- | Parameters used to implement Kademlia for TCP relays. | ||
83 | , tcpKademliaClient :: TCP.TCPClient String () Nonce8 | ||
84 | -- | This thread maintains the TCP relay table. | ||
85 | , tcpKademliaThread :: ThreadId | ||
86 | -- | Kademlia table of TCP relays. | ||
87 | , tcpBucketRefresher :: BucketRefresher NodeId TCP.NodeInfo | ||
78 | -- | Debug prints are written to this channel which is then flushed to | 88 | -- | Debug prints are written to this channel which is then flushed to |
79 | -- 'routeLogger'. | 89 | -- 'routeLogger'. |
80 | , routeLog :: TChan String | 90 | , routeLog :: TChan String |
@@ -138,9 +148,28 @@ gotTimeout rr = rr | |||
138 | 148 | ||
139 | newtype RouteEvent = BuildRoute RouteId | 149 | newtype RouteEvent = BuildRoute RouteId |
140 | 150 | ||
141 | newOnionRouter :: (String -> IO ()) -> IO OnionRouter | 151 | newOnionRouter :: TransportCrypto -> (String -> IO ()) -> IO OnionRouter |
142 | newOnionRouter perror = do | 152 | newOnionRouter crypto perror = do |
143 | drg0 <- drgNew | 153 | drg0 <- drgNew |
154 | (tbl,tcp) <- do | ||
155 | client <- TCP.newClient crypto | ||
156 | let addr = SockAddrInet 0 0 | ||
157 | tentative_udp = NodeInfo | ||
158 | { nodeId = key2id $ transportPublic crypto | ||
159 | , nodeIP = fromMaybe (toEnum 0) (fromSockAddr addr) | ||
160 | , nodePort = fromMaybe 0 $ sockAddrPort addr | ||
161 | } | ||
162 | tentative_info = TCP.NodeInfo tentative_udp (fromIntegral 443) | ||
163 | tbl <- atomically $ newTVar | ||
164 | $ R.nullTable (comparing TCP.nodeId) | ||
165 | (\s -> hashWithSalt s . TCP.nodeId) | ||
166 | tentative_info | ||
167 | R.defaultBucketCount | ||
168 | return $ (,) tbl TCP.TCPClient | ||
169 | { tcpCrypto = crypto | ||
170 | , tcpClient = client | ||
171 | , tcpGetGateway = selectGateway tbl | ||
172 | } | ||
144 | or <- atomically $ do | 173 | or <- atomically $ do |
145 | -- chan <- newTChan | 174 | -- chan <- newTChan |
146 | drg <- newTVar drg0 | 175 | drg <- newTVar drg0 |
@@ -152,6 +181,7 @@ newOnionRouter perror = do | |||
152 | tc <- newTVar 0 | 181 | tc <- newTVar 0 |
153 | pr <- newArray (0,11) 0 | 182 | pr <- newArray (0,11) 0 |
154 | rlog <- newTChan | 183 | rlog <- newTChan |
184 | refresher <- newBucketRefresher tbl (TCP.nodeSearch tcp) (fmap (maybe False $ const True) . TCP.tcpPing (TCP.tcpClient tcp)) | ||
155 | return OnionRouter | 185 | return OnionRouter |
156 | { pendingRoutes = pr | 186 | { pendingRoutes = pr |
157 | , onionDRG = drg | 187 | , onionDRG = drg |
@@ -160,14 +190,23 @@ newOnionRouter perror = do | |||
160 | , trampolineNodes = tn | 190 | , trampolineNodes = tn |
161 | , trampolineIds = ti | 191 | , trampolineIds = ti |
162 | , trampolineCount = tc | 192 | , trampolineCount = tc |
193 | , tcpKademliaClient = tcp | ||
194 | , tcpBucketRefresher = refresher | ||
163 | , routeLog = rlog | 195 | , routeLog = rlog |
164 | , routeThread = error "Failed to invoke forkRouteBuilder" | 196 | , routeThread = error "forkRouteBuilder not invoked (missing onion route builder thread)." |
197 | , tcpKademliaThread = error "forkRouteBuilder not invoked (missing TCP bucket maintenance thread)." | ||
165 | , routeLogger = perror | 198 | , routeLogger = perror |
166 | } | 199 | } |
167 | return or | 200 | return or |
168 | 201 | ||
202 | selectGateway :: TVar (R.BucketList TCP.NodeInfo) -> NodeInfo -> STM (Maybe TCP.NodeInfo) | ||
203 | selectGateway tbl ni = do | ||
204 | ns <- kclosest TCP.tcpSpace 2 (nodeId ni) <$> readTVar tbl | ||
205 | return $ listToMaybe $ dropWhile (\n -> TCP.nodeId n == nodeId ni) ns | ||
206 | |||
169 | forkRouteBuilder :: OnionRouter -> (NodeId -> NodeInfo -> IO (Maybe [NodeInfo])) -> IO OnionRouter | 207 | forkRouteBuilder :: OnionRouter -> (NodeId -> NodeInfo -> IO (Maybe [NodeInfo])) -> IO OnionRouter |
170 | forkRouteBuilder or getnodes = do | 208 | forkRouteBuilder or getnodes = do |
209 | bktsThread <- forkPollForRefresh $ tcpBucketRefresher or | ||
171 | tid <- forkIO $ do | 210 | tid <- forkIO $ do |
172 | me <- myThreadId | 211 | me <- myThreadId |
173 | labelThread me "OnionRouter" | 212 | labelThread me "OnionRouter" |
@@ -186,7 +225,8 @@ forkRouteBuilder or getnodes = do | |||
186 | in do event <- foldr1 orElse stms | 225 | in do event <- foldr1 orElse stms |
187 | return $ handleEvent getnodes or { routeThread = me } event) | 226 | return $ handleEvent getnodes or { routeThread = me } event) |
188 | io | 227 | io |
189 | return or { routeThread = tid } | 228 | return or { routeThread = tid |
229 | , tcpKademliaThread = bktsThread } | ||
190 | 230 | ||
191 | generateNodeId :: MonadRandom m => m NodeId | 231 | generateNodeId :: MonadRandom m => m NodeId |
192 | generateNodeId = either (error "unable to make random nodeid") | 232 | generateNodeId = either (error "unable to make random nodeid") |
diff --git a/Presence/Presence.hs b/Presence/Presence.hs index f8a18388..8cdd1cdc 100644 --- a/Presence/Presence.hs +++ b/Presence/Presence.hs | |||
@@ -745,7 +745,7 @@ deliverMessage state fail msg = | |||
745 | deliverToConsole state fail msg' | 745 | deliverToConsole state fail msg' |
746 | else do | 746 | else do |
747 | forM_ chans $ \(from',Conn { connChan=chan}) -> do | 747 | forM_ chans $ \(from',Conn { connChan=chan}) -> do |
748 | -- TODO: Cloning isn't really neccessary unless there are multiple | 748 | -- TODO: Cloning isn't really necessary unless there are multiple |
749 | -- destinations and we should probably transition to minimal cloning, | 749 | -- destinations and we should probably transition to minimal cloning, |
750 | -- or else we should distinguish between announcable stanzas and | 750 | -- or else we should distinguish between announcable stanzas and |
751 | -- consumable stanzas and announcables use write-only broadcast | 751 | -- consumable stanzas and announcables use write-only broadcast |
diff --git a/examples/dhtd.hs b/examples/dhtd.hs index 04b8c064..959383dc 100644 --- a/examples/dhtd.hs +++ b/examples/dhtd.hs | |||
@@ -73,6 +73,7 @@ import Network.UPNP as UPNP | |||
73 | import Network.Address hiding (NodeId, NodeInfo(..)) | 73 | import Network.Address hiding (NodeId, NodeInfo(..)) |
74 | import Network.QueryResponse | 74 | import Network.QueryResponse |
75 | import Network.StreamServer | 75 | import Network.StreamServer |
76 | import Network.Kademlia.Bootstrap (refreshBuckets,bootstrap) | ||
76 | import Network.Kademlia.CommonAPI | 77 | import Network.Kademlia.CommonAPI |
77 | import Network.Kademlia.Persistence | 78 | import Network.Kademlia.Persistence |
78 | import Network.Kademlia.Routing as R | 79 | import Network.Kademlia.Routing as R |
@@ -95,6 +96,7 @@ import qualified Network.Tox.DHT.Handlers as Tox | |||
95 | import qualified Network.Tox.Onion.Transport as Tox | 96 | import qualified Network.Tox.Onion.Transport as Tox |
96 | import qualified Network.Tox.Onion.Handlers as Tox | 97 | import qualified Network.Tox.Onion.Handlers as Tox |
97 | import qualified Network.Tox.Crypto.Transport as Tox | 98 | import qualified Network.Tox.Crypto.Transport as Tox |
99 | import qualified Network.Tox.TCP as TCP | ||
98 | import Data.Typeable | 100 | import Data.Typeable |
99 | import Network.Tox.ContactInfo as Tox | 101 | import Network.Tox.ContactInfo as Tox |
100 | import OnionRouter | 102 | import OnionRouter |
@@ -1316,6 +1318,8 @@ initTox opts ssvar keysdb mbxmpp invc = case porttox opts of | |||
1316 | 1318 | ||
1317 | toxSearches <- atomically $ newTVar Map.empty | 1319 | toxSearches <- atomically $ newTVar Map.empty |
1318 | 1320 | ||
1321 | tcpSearches <- atomically $ newTVar Map.empty | ||
1322 | |||
1319 | let toxDHT bkts wantip = DHT | 1323 | let toxDHT bkts wantip = DHT |
1320 | { dhtBuckets = bkts (Tox.toxRouting tox) | 1324 | { dhtBuckets = bkts (Tox.toxRouting tox) |
1321 | , dhtPing = Map.fromList | 1325 | , dhtPing = Map.fromList |
@@ -1486,11 +1490,36 @@ initTox opts ssvar keysdb mbxmpp invc = case porttox opts of | |||
1486 | Want_IP4 -> toxStrap4 | 1490 | Want_IP4 -> toxStrap4 |
1487 | Want_IP6 -> toxStrap6 | 1491 | Want_IP6 -> toxStrap6 |
1488 | } | 1492 | } |
1493 | tcpclient = tcpKademliaClient $ Tox.toxOnionRoutes tox | ||
1494 | tcpRefresher = tcpBucketRefresher $ Tox.toxOnionRoutes tox | ||
1495 | tcpDHT = DHT | ||
1496 | { dhtBuckets = refreshBuckets tcpRefresher | ||
1497 | , dhtSecretKey = return $ Just $ transportSecret (Tox.toxCryptoKeys tox) | ||
1498 | , dhtPing = Map.singleton "ping" DHTPing | ||
1499 | { pingQuery = noArgPing $ TCP.tcpPing (TCP.tcpClient tcpclient) | ||
1500 | , pingShowResult = show | ||
1501 | } | ||
1502 | , dhtQuery = Map.singleton "node" DHTQuery | ||
1503 | { qsearch = TCP.nodeSearch tcpclient | ||
1504 | , qhandler = \ni nid -> do | ||
1505 | ns <- R.kclosest (searchSpace $ TCP.nodeSearch tcpclient) searchK nid | ||
1506 | <$> atomically (readTVar $ refreshBuckets tcpRefresher) | ||
1507 | return (ns,ns,Just ()) | ||
1508 | , qshowR = show -- TCP.NodeInfo | ||
1509 | , qshowTok = (const Nothing) | ||
1510 | } | ||
1511 | , dhtAnnouncables = Map.empty | ||
1512 | , dhtParseId = readEither :: String -> Either String Tox.NodeId | ||
1513 | , dhtSearches = tcpSearches | ||
1514 | , dhtFallbackNodes = return [] | ||
1515 | , dhtBootstrap = bootstrap tcpRefresher | ||
1516 | } | ||
1489 | dhts = Map.fromList $ | 1517 | dhts = Map.fromList $ |
1490 | ("tox4", toxDHT Tox.routing4 Want_IP4) | 1518 | ("tox4", toxDHT Tox.routing4 Want_IP4) |
1491 | : if ip6tox opts | 1519 | : if ip6tox opts |
1492 | then [ ("tox6", toxDHT Tox.routing6 Want_IP6) ] | 1520 | then [ ("tox6", toxDHT Tox.routing6 Want_IP6) ] |
1493 | else [] | 1521 | else [] |
1522 | ++ [("toxtcp", tcpDHT)] | ||
1494 | ips :: IO [SockAddr] | 1523 | ips :: IO [SockAddr] |
1495 | ips = readExternals Tox.nodeAddr [ Tox.routing4 $ Tox.toxRouting tox | 1524 | ips = readExternals Tox.nodeAddr [ Tox.routing4 $ Tox.toxRouting tox |
1496 | , Tox.routing6 $ Tox.toxRouting tox ] | 1525 | , Tox.routing6 $ Tox.toxRouting tox ] |
@@ -1668,7 +1697,8 @@ main = do | |||
1668 | installHandler sigINT (CatchOnce (atomically $ writeTVar signalQuit True)) Nothing | 1697 | installHandler sigINT (CatchOnce (atomically $ writeTVar signalQuit True)) Nothing |
1669 | let defaultToxData = do | 1698 | let defaultToxData = do |
1670 | rster <- Tox.newContactInfo | 1699 | rster <- Tox.newContactInfo |
1671 | orouter <- newOnionRouter (dput XMisc) | 1700 | crypto <- newCrypto |
1701 | orouter <- newOnionRouter crypto (dput XMisc) | ||
1672 | return (rster, orouter) | 1702 | return (rster, orouter) |
1673 | (rstr,orouter) <- fromMaybe defaultToxData $ do | 1703 | (rstr,orouter) <- fromMaybe defaultToxData $ do |
1674 | tox <- mbtox | 1704 | tox <- mbtox |
diff --git a/src/Network/BitTorrent/MainlineDHT.hs b/src/Network/BitTorrent/MainlineDHT.hs index 573efcba..a29657af 100644 --- a/src/Network/BitTorrent/MainlineDHT.hs +++ b/src/Network/BitTorrent/MainlineDHT.hs | |||
@@ -563,11 +563,11 @@ newClient swarms addr = do | |||
563 | -- have a client to send queries with. | 563 | -- have a client to send queries with. |
564 | let nullPing = const $ return False | 564 | let nullPing = const $ return False |
565 | nullSearch = mainlineSearch $ \_ _ -> return Nothing | 565 | nullSearch = mainlineSearch $ \_ _ -> return Nothing |
566 | refresher4 <- newBucketRefresher tentative_info nullSearch nullPing | 566 | tbl4 <- newTVar $ R.nullTable (comparing nodeId) (\s -> hashWithSalt s . nodeId) tentative_info R.defaultBucketCount |
567 | refresher6 <- newBucketRefresher tentative_info6 nullSearch nullPing | 567 | refresher4 <- newBucketRefresher tbl4 nullSearch nullPing |
568 | let tbl4 = refreshBuckets refresher4 | 568 | tbl6 <- newTVar $ R.nullTable (comparing nodeId) (\s -> hashWithSalt s . nodeId) tentative_info6 R.defaultBucketCount |
569 | tbl6 = refreshBuckets refresher6 | 569 | refresher6 <- newBucketRefresher tbl6 nullSearch nullPing |
570 | updateIPVote tblvar addrvar a = do | 570 | let updateIPVote tblvar addrvar a = do |
571 | bkts <- readTVar tblvar | 571 | bkts <- readTVar tblvar |
572 | case bep42 a (nodeId $ R.thisNode bkts) of | 572 | case bep42 a (nodeId $ R.thisNode bkts) of |
573 | Just nid -> do | 573 | Just nid -> do |
diff --git a/src/Network/Kademlia.hs b/src/Network/Kademlia.hs index 44ef2ec1..488a53ac 100644 --- a/src/Network/Kademlia.hs +++ b/src/Network/Kademlia.hs | |||
@@ -66,7 +66,7 @@ contramapIR f ir = InsertionReporter | |||
66 | , reportPingResult = \tm ni b -> reportPingResult ir tm (f ni) b | 66 | , reportPingResult = \tm ni b -> reportPingResult ir tm (f ni) b |
67 | } | 67 | } |
68 | 68 | ||
69 | -- | All the IO operations neccessary to maintain a Kademlia routing table. | 69 | -- | All the IO operations necessary to maintain a Kademlia routing table. |
70 | data TableStateIO ni = TableStateIO | 70 | data TableStateIO ni = TableStateIO |
71 | { -- | Write the routing table. Typically 'writeTVar'. | 71 | { -- | Write the routing table. Typically 'writeTVar'. |
72 | tblWrite :: R.BucketList ni -> STM () | 72 | tblWrite :: R.BucketList ni -> STM () |
@@ -99,7 +99,7 @@ vanillaIO var ping = TableStateIO | |||
99 | , tblTransition = const $ return $ return () | 99 | , tblTransition = const $ return $ return () |
100 | } | 100 | } |
101 | 101 | ||
102 | -- | Everything neccessary to maintain a routing table of /ni/ (node | 102 | -- | Everything necessary to maintain a routing table of /ni/ (node |
103 | -- information) entries. | 103 | -- information) entries. |
104 | data Kademlia nid ni = Kademlia (InsertionReporter ni) | 104 | data Kademlia nid ni = Kademlia (InsertionReporter ni) |
105 | (KademliaSpace nid ni) | 105 | (KademliaSpace nid ni) |
@@ -109,7 +109,7 @@ data Kademlia nid ni = Kademlia (InsertionReporter ni) | |||
109 | -- Helper to 'insertNode'. | 109 | -- Helper to 'insertNode'. |
110 | -- | 110 | -- |
111 | -- Adapt return value from 'updateForPingResult' into a | 111 | -- Adapt return value from 'updateForPingResult' into a |
112 | -- more easily groked list of transitions. | 112 | -- more easily grokked list of transitions. |
113 | transition :: (ni,Maybe (t,ni)) -> [RoutingTransition ni] | 113 | transition :: (ni,Maybe (t,ni)) -> [RoutingTransition ni] |
114 | transition (x,m) = | 114 | transition (x,m) = |
115 | -- Just _ <- m = Node transition: Accepted --> Stranger | 115 | -- Just _ <- m = Node transition: Accepted --> Stranger |
diff --git a/src/Network/Kademlia/Bootstrap.hs b/src/Network/Kademlia/Bootstrap.hs index aad8a81e..0f5d4e4d 100644 --- a/src/Network/Kademlia/Bootstrap.hs +++ b/src/Network/Kademlia/Bootstrap.hs | |||
@@ -77,14 +77,14 @@ data BucketRefresher nid ni = forall tok addr. Ord addr => BucketRefresher | |||
77 | 77 | ||
78 | newBucketRefresher :: ( Ord addr, Hashable addr | 78 | newBucketRefresher :: ( Ord addr, Hashable addr |
79 | , SensibleNodeId nid ni ) | 79 | , SensibleNodeId nid ni ) |
80 | => ni | 80 | => TVar (R.BucketList ni) |
81 | -> Search nid addr tok ni ni | 81 | -> Search nid addr tok ni ni |
82 | -> (ni -> IO Bool) | 82 | -> (ni -> IO Bool) |
83 | -> STM (BucketRefresher nid ni) | 83 | -> STM (BucketRefresher nid ni) |
84 | newBucketRefresher template_ni sch ping = do | 84 | newBucketRefresher bkts sch ping = do |
85 | let spc = searchSpace sch | 85 | let spc = searchSpace sch |
86 | nodeId = kademliaLocation spc | 86 | nodeId = kademliaLocation spc |
87 | bkts <- newTVar $ R.nullTable (comparing nodeId) (\s -> hashWithSalt s . nodeId) template_ni R.defaultBucketCount | 87 | -- bkts <- newTVar $ R.nullTable (comparing nodeId) (\s -> hashWithSalt s . nodeId) template_ni R.defaultBucketCount |
88 | sched <- newTVar Int.empty | 88 | sched <- newTVar Int.empty |
89 | lasttouch <- newTVar 0 -- Would use getPOSIXTime here, or minBound, but alas... | 89 | lasttouch <- newTVar 0 -- Would use getPOSIXTime here, or minBound, but alas... |
90 | bootstrapVar <- newTVar True -- Start in bootstrapping mode. | 90 | bootstrapVar <- newTVar True -- Start in bootstrapping mode. |
diff --git a/src/Network/Tox.hs b/src/Network/Tox.hs index b98252d3..1e82c0c4 100644 --- a/src/Network/Tox.hs +++ b/src/Network/Tox.hs | |||
@@ -285,15 +285,16 @@ newToxOverTransport keydb addr onNewSession suppliedDHTKey udp tcp = do | |||
285 | let lookupClose _ = return Nothing | 285 | let lookupClose _ = return Nothing |
286 | 286 | ||
287 | mkrouting <- DHT.newRouting addr crypto updateIP updateIP | 287 | mkrouting <- DHT.newRouting addr crypto updateIP updateIP |
288 | orouter <- newOnionRouter $ dput XRoutes | 288 | orouter <- newOnionRouter crypto $ dput XRoutes |
289 | (cryptonet,dhtcrypt,onioncrypt,dtacrypt,handshakes) <- toxTransport crypto orouter lookupClose udp tcp | 289 | (cryptonet,dhtcrypt,onioncrypt,dtacrypt,handshakes) <- toxTransport crypto orouter lookupClose udp tcp |
290 | sessions <- initSessions (sendMessage cryptonet) | 290 | sessions <- initSessions (sendMessage cryptonet) |
291 | 291 | ||
292 | let dhtnet0 = layerTransportM (DHT.decrypt crypto) (DHT.encrypt crypto) dhtcrypt | 292 | let dhtnet0 = layerTransportM (DHT.decrypt crypto) (DHT.encrypt crypto) dhtcrypt |
293 | tbl4 = DHT.routing4 $ mkrouting (error "missing client") | 293 | tbl4 = DHT.routing4 $ mkrouting (error "missing client") |
294 | tbl6 = DHT.routing6 $ mkrouting (error "missing client") | 294 | tbl6 = DHT.routing6 $ mkrouting (error "missing client") |
295 | updateOnion bkts tr = hookBucketList DHT.toxSpace bkts orouter tr | ||
295 | dhtclient <- newClient drg dhtnet0 DHT.classify (myAddr tbl4 tbl6) (DHT.handlers crypto . mkrouting) id | 296 | dhtclient <- newClient drg dhtnet0 DHT.classify (myAddr tbl4 tbl6) (DHT.handlers crypto . mkrouting) id |
296 | $ \client net -> onInbound (DHT.updateRouting client (mkrouting client) orouter) net | 297 | $ \client net -> onInbound (DHT.updateRouting client (mkrouting client) updateOnion) net |
297 | 298 | ||
298 | hscache <- newHandshakeCache crypto (sendMessage handshakes) | 299 | hscache <- newHandshakeCache crypto (sendMessage handshakes) |
299 | let sparams = SessionParams | 300 | let sparams = SessionParams |
diff --git a/src/Network/Tox/DHT/Handlers.hs b/src/Network/Tox/DHT/Handlers.hs index 2062b51d..2fbac5d3 100644 --- a/src/Network/Tox/DHT/Handlers.hs +++ b/src/Network/Tox/DHT/Handlers.hs | |||
@@ -18,7 +18,8 @@ import Network.Address (WantIP (..), ipFamily, fromSockAddr, sockA | |||
18 | import qualified Network.Kademlia.Routing as R | 18 | import qualified Network.Kademlia.Routing as R |
19 | import Control.TriadCommittee | 19 | import Control.TriadCommittee |
20 | import System.Global6 | 20 | import System.Global6 |
21 | import OnionRouter | 21 | import DPut |
22 | import DebugTag | ||
22 | 23 | ||
23 | import qualified Data.ByteArray as BA | 24 | import qualified Data.ByteArray as BA |
24 | import qualified Data.ByteString.Char8 as C8 | 25 | import qualified Data.ByteString.Char8 as C8 |
@@ -27,6 +28,8 @@ import Control.Arrow | |||
27 | import Control.Monad | 28 | import Control.Monad |
28 | import Control.Concurrent.Lifted.Instrument | 29 | import Control.Concurrent.Lifted.Instrument |
29 | import Control.Concurrent.STM | 30 | import Control.Concurrent.STM |
31 | import Data.Hashable | ||
32 | import Data.Ord | ||
30 | import Data.Time.Clock.POSIX (POSIXTime, getPOSIXTime) | 33 | import Data.Time.Clock.POSIX (POSIXTime, getPOSIXTime) |
31 | import Network.Socket | 34 | import Network.Socket |
32 | import qualified Data.HashMap.Strict as HashMap | 35 | import qualified Data.HashMap.Strict as HashMap |
@@ -39,8 +42,6 @@ import Data.IP | |||
39 | import Data.Maybe | 42 | import Data.Maybe |
40 | import Data.Serialize (Serialize) | 43 | import Data.Serialize (Serialize) |
41 | import Data.Word | 44 | import Data.Word |
42 | import DPut | ||
43 | import DebugTag | ||
44 | 45 | ||
45 | data TransactionId = TransactionId | 46 | data TransactionId = TransactionId |
46 | { transactionKey :: Nonce8 -- ^ Used to lookup pending query. | 47 | { transactionKey :: Nonce8 -- ^ Used to lookup pending query. |
@@ -195,10 +196,10 @@ newRouting addr crypto update4 update6 = do | |||
195 | , searchNodeAddress = nodeIP &&& nodePort | 196 | , searchNodeAddress = nodeIP &&& nodePort |
196 | , searchQuery = \_ _ -> return Nothing | 197 | , searchQuery = \_ _ -> return Nothing |
197 | } | 198 | } |
198 | refresher4 <- newBucketRefresher tentative_info4 nullSearch nullPing | 199 | tbl4 <- newTVar $ R.nullTable (comparing nodeId) (\s -> hashWithSalt s . nodeId) tentative_info4 R.defaultBucketCount |
199 | refresher6 <- newBucketRefresher tentative_info6 nullSearch nullPing | 200 | tbl6 <- newTVar $ R.nullTable (comparing nodeId) (\s -> hashWithSalt s . nodeId) tentative_info6 R.defaultBucketCount |
200 | let tbl4 = refreshBuckets refresher4 | 201 | refresher4 <- newBucketRefresher tbl4 nullSearch nullPing |
201 | tbl6 = refreshBuckets refresher6 | 202 | refresher6 <- newBucketRefresher tbl6 nullSearch nullPing |
202 | committee4 <- newTriadCommittee (update4 tbl4) -- updateIPVote tbl4 addr4 | 203 | committee4 <- newTriadCommittee (update4 tbl4) -- updateIPVote tbl4 addr4 |
203 | committee6 <- newTriadCommittee (update6 tbl6) -- updateIPVote tbl6 addr6 | 204 | committee6 <- newTriadCommittee (update6 tbl6) -- updateIPVote tbl6 addr6 |
204 | cbvar <- newTVar HashMap.empty | 205 | cbvar <- newTVar HashMap.empty |
@@ -412,7 +413,11 @@ getNodes client cbvar nid addr = do | |||
412 | rumoredAddress cb now (nodeAddr addr) n | 413 | rumoredAddress cb now (nodeAddr addr) n |
413 | return $ fmap unwrapNodes $ join reply | 414 | return $ fmap unwrapNodes $ join reply |
414 | 415 | ||
415 | updateRouting :: Client -> Routing -> OnionRouter -> NodeInfo -> Message -> IO () | 416 | updateRouting :: Client -> Routing |
417 | -> (TVar (R.BucketList NodeInfo) -> RoutingTransition NodeInfo -> STM ()) | ||
418 | -> NodeInfo | ||
419 | -> Message | ||
420 | -> IO () | ||
416 | updateRouting client routing orouter naddr msg | 421 | updateRouting client routing orouter naddr msg |
417 | | PacketKind 0x21 <- msgType msg = -- dput XLan "(tox)updateRouting: ignoring lan discovery" -- ignore lan discovery | 422 | | PacketKind 0x21 <- msgType msg = -- dput XLan "(tox)updateRouting: ignoring lan discovery" -- ignore lan discovery |
418 | -- Ignore lan announcements until they reply to our ping. | 423 | -- Ignore lan announcements until they reply to our ping. |
@@ -431,7 +436,11 @@ updateRouting client routing orouter naddr msg | |||
431 | Want_Both -> do dput XMisc "BUG:unreachable" | 436 | Want_Both -> do dput XMisc "BUG:unreachable" |
432 | error $ "BUG:unreachable at " ++ __FILE__ ++ ":" ++ show __LINE__ | 437 | error $ "BUG:unreachable at " ++ __FILE__ ++ ":" ++ show __LINE__ |
433 | 438 | ||
434 | updateTable :: Client -> NodeInfo -> OnionRouter -> TriadCommittee NodeId SockAddr -> BucketRefresher NodeId NodeInfo -> IO () | 439 | updateTable :: Client -> NodeInfo |
440 | -> (TVar (R.BucketList NodeInfo) -> RoutingTransition NodeInfo -> STM ()) | ||
441 | -> TriadCommittee NodeId SockAddr | ||
442 | -> BucketRefresher NodeId NodeInfo | ||
443 | -> IO () | ||
435 | updateTable client naddr orouter committee refresher = do | 444 | updateTable client naddr orouter committee refresher = do |
436 | self <- atomically $ R.thisNode <$> readTVar (refreshBuckets refresher) | 445 | self <- atomically $ R.thisNode <$> readTVar (refreshBuckets refresher) |
437 | -- dput XMisc $ "(tox)updateRouting: " ++ show (nodeIP self, nodeIP naddr) | 446 | -- dput XMisc $ "(tox)updateRouting: " ++ show (nodeIP self, nodeIP naddr) |
@@ -439,7 +448,9 @@ updateTable client naddr orouter committee refresher = do | |||
439 | -- TODO: IP address vote? | 448 | -- TODO: IP address vote? |
440 | insertNode (toxKademlia client committee orouter refresher) naddr | 449 | insertNode (toxKademlia client committee orouter refresher) naddr |
441 | 450 | ||
442 | toxKademlia :: Client -> TriadCommittee NodeId SockAddr -> OnionRouter | 451 | toxKademlia :: Client |
452 | -> TriadCommittee NodeId SockAddr | ||
453 | -> (TVar (R.BucketList NodeInfo) -> RoutingTransition NodeInfo -> STM ()) | ||
443 | -> BucketRefresher NodeId NodeInfo | 454 | -> BucketRefresher NodeId NodeInfo |
444 | -> Kademlia NodeId NodeInfo | 455 | -> Kademlia NodeId NodeInfo |
445 | toxKademlia client committee orouter refresher | 456 | toxKademlia client committee orouter refresher |
@@ -449,7 +460,8 @@ toxKademlia client committee orouter refresher | |||
449 | { tblTransition = \tr -> do | 460 | { tblTransition = \tr -> do |
450 | io1 <- transitionCommittee committee tr | 461 | io1 <- transitionCommittee committee tr |
451 | io2 <- touchBucket refresher tr -- toxSpace (15*60) var sched tr | 462 | io2 <- touchBucket refresher tr -- toxSpace (15*60) var sched tr |
452 | hookBucketList toxSpace (refreshBuckets refresher) orouter tr | 463 | -- hookBucketList toxSpace (refreshBuckets refresher) orouter tr |
464 | orouter (refreshBuckets refresher) tr | ||
453 | return $ do | 465 | return $ do |
454 | io1 >> io2 | 466 | io1 >> io2 |
455 | {- | 467 | {- |
diff --git a/src/Network/Tox/NodeId.hs b/src/Network/Tox/NodeId.hs index 98be1e3a..1c68249e 100644 --- a/src/Network/Tox/NodeId.hs +++ b/src/Network/Tox/NodeId.hs | |||
@@ -320,7 +320,7 @@ instance Read NodeInfo where | |||
320 | RP.skipSpaces | 320 | RP.skipSpaces |
321 | let n = 43 -- characters in node id. | 321 | let n = 43 -- characters in node id. |
322 | parseAddr = RP.between (RP.char '(') (RP.char ')') (RP.munch (/=')')) | 322 | parseAddr = RP.between (RP.char '(') (RP.char ')') (RP.munch (/=')')) |
323 | RP.+++ RP.munch (not . isSpace) | 323 | RP.+++ RP.munch (\c -> not (isSpace c) && not (c `elem` ("{}()"::[Char]))) |
324 | nodeidAt = do hexhash <- sequence $ replicate n (RP.satisfy b64digit) | 324 | nodeidAt = do hexhash <- sequence $ replicate n (RP.satisfy b64digit) |
325 | RP.char '@' RP.+++ RP.satisfy isSpace | 325 | RP.char '@' RP.+++ RP.satisfy isSpace |
326 | addrstr <- parseAddr | 326 | addrstr <- parseAddr |