summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--OnionRouter.hs50
-rw-r--r--Presence/Presence.hs2
-rw-r--r--examples/dhtd.hs32
-rw-r--r--src/Network/BitTorrent/MainlineDHT.hs10
-rw-r--r--src/Network/Kademlia.hs6
-rw-r--r--src/Network/Kademlia/Bootstrap.hs6
-rw-r--r--src/Network/Tox.hs5
-rw-r--r--src/Network/Tox/DHT/Handlers.hs34
-rw-r--r--src/Network/Tox/NodeId.hs2
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
6import Crypto.Tox 6import Crypto.Tox
7import Network.Address 7import Network.Address
8import Network.Kademlia 8import Network.Kademlia
9import Network.Kademlia.Routing 9import Network.Kademlia.Bootstrap
10import Network.Kademlia.Routing as R
10import Network.QueryResponse 11import Network.QueryResponse
11import Network.Tox.NodeId 12import Network.Tox.NodeId
12import Network.Tox.Onion.Transport 13import Network.Tox.Onion.Transport
14import qualified Network.Tox.TCP as TCP
13 15
14import Control.Concurrent.STM 16import Control.Concurrent.STM
15import Control.Concurrent.STM.TArray 17import Control.Concurrent.STM.TArray
@@ -20,11 +22,13 @@ import Data.Bits
20import Data.Bool 22import Data.Bool
21import Data.List 23import Data.List
22import qualified Data.ByteString as B 24import qualified Data.ByteString as B
25import Data.Hashable
23import qualified Data.HashMap.Strict as HashMap 26import qualified Data.HashMap.Strict as HashMap
24 ;import Data.HashMap.Strict (HashMap) 27 ;import Data.HashMap.Strict (HashMap)
25import qualified Data.IntMap as IntMap 28import qualified Data.IntMap as IntMap
26 ;import Data.IntMap (IntMap) 29 ;import Data.IntMap (IntMap)
27import Data.Maybe 30import Data.Maybe
31import Data.Ord
28import qualified Data.Serialize as S 32import qualified Data.Serialize as S
29import Data.Time.Clock.POSIX 33import Data.Time.Clock.POSIX
30import Data.Typeable 34import 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
139newtype RouteEvent = BuildRoute RouteId 149newtype RouteEvent = BuildRoute RouteId
140 150
141newOnionRouter :: (String -> IO ()) -> IO OnionRouter 151newOnionRouter :: TransportCrypto -> (String -> IO ()) -> IO OnionRouter
142newOnionRouter perror = do 152newOnionRouter 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
202selectGateway :: TVar (R.BucketList TCP.NodeInfo) -> NodeInfo -> STM (Maybe TCP.NodeInfo)
203selectGateway 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
169forkRouteBuilder :: OnionRouter -> (NodeId -> NodeInfo -> IO (Maybe [NodeInfo])) -> IO OnionRouter 207forkRouteBuilder :: OnionRouter -> (NodeId -> NodeInfo -> IO (Maybe [NodeInfo])) -> IO OnionRouter
170forkRouteBuilder or getnodes = do 208forkRouteBuilder 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
191generateNodeId :: MonadRandom m => m NodeId 231generateNodeId :: MonadRandom m => m NodeId
192generateNodeId = either (error "unable to make random nodeid") 232generateNodeId = 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
73import Network.Address hiding (NodeId, NodeInfo(..)) 73import Network.Address hiding (NodeId, NodeInfo(..))
74import Network.QueryResponse 74import Network.QueryResponse
75import Network.StreamServer 75import Network.StreamServer
76import Network.Kademlia.Bootstrap (refreshBuckets,bootstrap)
76import Network.Kademlia.CommonAPI 77import Network.Kademlia.CommonAPI
77import Network.Kademlia.Persistence 78import Network.Kademlia.Persistence
78import Network.Kademlia.Routing as R 79import Network.Kademlia.Routing as R
@@ -95,6 +96,7 @@ import qualified Network.Tox.DHT.Handlers as Tox
95import qualified Network.Tox.Onion.Transport as Tox 96import qualified Network.Tox.Onion.Transport as Tox
96import qualified Network.Tox.Onion.Handlers as Tox 97import qualified Network.Tox.Onion.Handlers as Tox
97import qualified Network.Tox.Crypto.Transport as Tox 98import qualified Network.Tox.Crypto.Transport as Tox
99import qualified Network.Tox.TCP as TCP
98import Data.Typeable 100import Data.Typeable
99import Network.Tox.ContactInfo as Tox 101import Network.Tox.ContactInfo as Tox
100import OnionRouter 102import 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.
70data TableStateIO ni = TableStateIO 70data 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.
104data Kademlia nid ni = Kademlia (InsertionReporter ni) 104data 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.
113transition :: (ni,Maybe (t,ni)) -> [RoutingTransition ni] 113transition :: (ni,Maybe (t,ni)) -> [RoutingTransition ni]
114transition (x,m) = 114transition (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
78newBucketRefresher :: ( Ord addr, Hashable addr 78newBucketRefresher :: ( 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)
84newBucketRefresher template_ni sch ping = do 84newBucketRefresher 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
18import qualified Network.Kademlia.Routing as R 18import qualified Network.Kademlia.Routing as R
19import Control.TriadCommittee 19import Control.TriadCommittee
20import System.Global6 20import System.Global6
21import OnionRouter 21import DPut
22import DebugTag
22 23
23import qualified Data.ByteArray as BA 24import qualified Data.ByteArray as BA
24import qualified Data.ByteString.Char8 as C8 25import qualified Data.ByteString.Char8 as C8
@@ -27,6 +28,8 @@ import Control.Arrow
27import Control.Monad 28import Control.Monad
28import Control.Concurrent.Lifted.Instrument 29import Control.Concurrent.Lifted.Instrument
29import Control.Concurrent.STM 30import Control.Concurrent.STM
31import Data.Hashable
32import Data.Ord
30import Data.Time.Clock.POSIX (POSIXTime, getPOSIXTime) 33import Data.Time.Clock.POSIX (POSIXTime, getPOSIXTime)
31import Network.Socket 34import Network.Socket
32import qualified Data.HashMap.Strict as HashMap 35import qualified Data.HashMap.Strict as HashMap
@@ -39,8 +42,6 @@ import Data.IP
39import Data.Maybe 42import Data.Maybe
40import Data.Serialize (Serialize) 43import Data.Serialize (Serialize)
41import Data.Word 44import Data.Word
42import DPut
43import DebugTag
44 45
45data TransactionId = TransactionId 46data 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
415updateRouting :: Client -> Routing -> OnionRouter -> NodeInfo -> Message -> IO () 416updateRouting :: Client -> Routing
417 -> (TVar (R.BucketList NodeInfo) -> RoutingTransition NodeInfo -> STM ())
418 -> NodeInfo
419 -> Message
420 -> IO ()
416updateRouting client routing orouter naddr msg 421updateRouting 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
434updateTable :: Client -> NodeInfo -> OnionRouter -> TriadCommittee NodeId SockAddr -> BucketRefresher NodeId NodeInfo -> IO () 439updateTable :: Client -> NodeInfo
440 -> (TVar (R.BucketList NodeInfo) -> RoutingTransition NodeInfo -> STM ())
441 -> TriadCommittee NodeId SockAddr
442 -> BucketRefresher NodeId NodeInfo
443 -> IO ()
435updateTable client naddr orouter committee refresher = do 444updateTable 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
442toxKademlia :: Client -> TriadCommittee NodeId SockAddr -> OnionRouter 451toxKademlia :: 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
445toxKademlia client committee orouter refresher 456toxKademlia 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