diff options
-rw-r--r-- | OnionRouter.hs | 8 | ||||
-rw-r--r-- | TCPProber.hs | 162 | ||||
-rw-r--r-- | examples/dhtd.hs | 6 | ||||
-rwxr-xr-x | g | 2 | ||||
-rw-r--r-- | src/Network/Tox.hs | 6 | ||||
-rw-r--r-- | src/Network/Tox/TCP.hs | 52 |
6 files changed, 222 insertions, 14 deletions
diff --git a/OnionRouter.hs b/OnionRouter.hs index 55ba9c28..39b3a872 100644 --- a/OnionRouter.hs +++ b/OnionRouter.hs | |||
@@ -12,6 +12,7 @@ import Network.QueryResponse | |||
12 | import Network.Tox.NodeId | 12 | import Network.Tox.NodeId |
13 | import Network.Tox.Onion.Transport | 13 | import Network.Tox.Onion.Transport |
14 | import qualified Network.Tox.TCP as TCP | 14 | import qualified Network.Tox.TCP as TCP |
15 | import qualified TCPProber as TCP | ||
15 | 16 | ||
16 | import Control.Concurrent.STM | 17 | import Control.Concurrent.STM |
17 | import Control.Concurrent.STM.TArray | 18 | import Control.Concurrent.STM.TArray |
@@ -83,6 +84,8 @@ data OnionRouter = OnionRouter | |||
83 | , tcpKademliaClient :: TCP.TCPClient String () Nonce8 | 84 | , tcpKademliaClient :: TCP.TCPClient String () Nonce8 |
84 | -- | This thread maintains the TCP relay table. | 85 | -- | This thread maintains the TCP relay table. |
85 | , tcpKademliaThread :: ThreadId | 86 | , tcpKademliaThread :: ThreadId |
87 | , tcpProber :: TCP.TCPProber | ||
88 | , tcpProberThread :: ThreadId | ||
86 | -- | Kademlia table of TCP relays. | 89 | -- | Kademlia table of TCP relays. |
87 | , tcpBucketRefresher :: BucketRefresher NodeId TCP.NodeInfo | 90 | , tcpBucketRefresher :: BucketRefresher NodeId TCP.NodeInfo |
88 | -- | Debug prints are written to this channel which is then flushed to | 91 | -- | Debug prints are written to this channel which is then flushed to |
@@ -181,7 +184,8 @@ newOnionRouter crypto perror = do | |||
181 | tc <- newTVar 0 | 184 | tc <- newTVar 0 |
182 | pr <- newArray (0,11) 0 | 185 | pr <- newArray (0,11) 0 |
183 | rlog <- newTChan | 186 | rlog <- newTChan |
184 | refresher <- newBucketRefresher tbl (TCP.nodeSearch tcp) (fmap (maybe False $ const True) . TCP.tcpPing (TCP.tcpClient tcp)) | 187 | prober <- TCP.newProber |
188 | refresher <- newBucketRefresher tbl (TCP.nodeSearch prober tcp) (fmap (maybe False $ const True) . TCP.tcpPing (TCP.tcpClient tcp)) | ||
185 | return OnionRouter | 189 | return OnionRouter |
186 | { pendingRoutes = pr | 190 | { pendingRoutes = pr |
187 | , onionDRG = drg | 191 | , onionDRG = drg |
@@ -202,6 +206,8 @@ newOnionRouter crypto perror = do | |||
202 | , routeLog = rlog | 206 | , routeLog = rlog |
203 | , routeThread = error "forkRouteBuilder not invoked (missing onion route builder thread)." | 207 | , routeThread = error "forkRouteBuilder not invoked (missing onion route builder thread)." |
204 | , tcpKademliaThread = error "forkRouteBuilder not invoked (missing TCP bucket maintenance thread)." | 208 | , tcpKademliaThread = error "forkRouteBuilder not invoked (missing TCP bucket maintenance thread)." |
209 | , tcpProber = prober | ||
210 | , tcpProberThread = error "forkRouteBuilder not invoked (missing TCP probe thread)." | ||
205 | , routeLogger = perror | 211 | , routeLogger = perror |
206 | } | 212 | } |
207 | return or | 213 | return or |
diff --git a/TCPProber.hs b/TCPProber.hs new file mode 100644 index 00000000..8d468e53 --- /dev/null +++ b/TCPProber.hs | |||
@@ -0,0 +1,162 @@ | |||
1 | {-# LANGUAGE LambdaCase #-} | ||
2 | module TCPProber where | ||
3 | |||
4 | import Control.Concurrent | ||
5 | import GHC.Conc | ||
6 | |||
7 | import Control.Arrow | ||
8 | import Control.Concurrent.STM | ||
9 | import Control.Monad | ||
10 | import Data.Function | ||
11 | import Data.IP | ||
12 | import Data.Maybe | ||
13 | import Data.Time.Clock.POSIX | ||
14 | import Network.Socket | ||
15 | import System.Timeout | ||
16 | |||
17 | import Crypto.Tox | ||
18 | import Data.Wrapper.PSQ as PSQ | ||
19 | import Network.Kademlia.Search | ||
20 | import Network.Tox.NodeId | ||
21 | import qualified Network.Tox.TCP as TCP | ||
22 | |||
23 | resolvePort :: TCP.RelayClient -> NodeInfo -> IO (Maybe PortNumber) | ||
24 | resolvePort tcp ni = do | ||
25 | got <- newTVarIO Nothing | ||
26 | cnt <- newTVarIO 0 | ||
27 | let n port = TCP.NodeInfo ni port | ||
28 | forkPort port = do | ||
29 | atomically $ modifyTVar' cnt succ | ||
30 | t <- forkIO $ do | ||
31 | m <- TCP.tcpPing tcp $ n port | ||
32 | atomically $ do | ||
33 | mg <- readTVar got | ||
34 | when (isNothing mg) | ||
35 | $ forM_ m $ \_ -> writeTVar got $ Just port | ||
36 | modifyTVar' cnt pred | ||
37 | labelThread t $ "probe." ++ show port ++ "." ++ show (nodeId ni) | ||
38 | return t | ||
39 | readResult = atomically $ do | ||
40 | m <- readTVar got | ||
41 | case m of | ||
42 | Just v -> return $ Just v | ||
43 | Nothing -> readTVar cnt >>= check . (== 0) >> return Nothing | ||
44 | t443 <- forkPort 443 | ||
45 | t80 <- forkPort 80 | ||
46 | p <- timeout 1000000 readResult >>= \case | ||
47 | Just (Just p) -> do | ||
48 | killThread t443 | ||
49 | killThread t80 | ||
50 | return $ Just p | ||
51 | _ -> do | ||
52 | let uport = nodePort ni | ||
53 | tudp <- forM (guard $ uport `notElem` [443,80,3389,33445]) | ||
54 | $ \() -> forkPort uport | ||
55 | t3389 <- forkPort 3389 | ||
56 | t33445 <- forkPort 33445 | ||
57 | p <- readResult | ||
58 | mapM_ killThread [t443,t80,t3389,t33445] | ||
59 | mapM_ killThread (tudp :: Maybe ThreadId) | ||
60 | return p | ||
61 | return p | ||
62 | |||
63 | data TCPProber = TCPProber | ||
64 | { probeQueue :: TVar (PSQ' NodeId POSIXTime SockAddr{-UDP-}) | ||
65 | , probeSpill :: TVar (PSQ' NodeId POSIXTime SockAddr{-UDP-}) | ||
66 | , probeSpillCount :: TVar Int -- Data.HashPSQ has O(n) size, so we keep a count. | ||
67 | , probeCache :: TVar (PSQ' NodeId POSIXTime (SockAddr{-UDP-},PortNumber{-TCP-})) | ||
68 | , probeCacheCount :: TVar Int | ||
69 | } | ||
70 | |||
71 | newProber :: STM TCPProber | ||
72 | newProber = do | ||
73 | q <- newTVar PSQ.empty | ||
74 | spill <- newTVar PSQ.empty | ||
75 | spillcnt <- newTVar 0 | ||
76 | cache <- newTVar PSQ.empty | ||
77 | cachecnt <- newTVar 0 | ||
78 | return TCPProber | ||
79 | { probeQueue = q | ||
80 | , probeSpill = spill | ||
81 | , probeSpillCount = spillcnt | ||
82 | , probeCache = cache | ||
83 | , probeCacheCount = cachecnt | ||
84 | } | ||
85 | |||
86 | |||
87 | enqueueProbe :: TCPProber -> NodeInfo -> IO () | ||
88 | enqueueProbe prober ni = do | ||
89 | tm <- getPOSIXTime | ||
90 | atomically $ do | ||
91 | spill <- readTVar (probeSpill prober) | ||
92 | cache <- readTVar (probeCache prober) | ||
93 | q <- readTVar (probeQueue prober) | ||
94 | let bump var x = modifyTVar' var $ insert' (nodeId ni) x tm | ||
95 | case PSQ.lookup (nodeId ni) cache of | ||
96 | Just (tm, x) -> bump (probeCache prober) x | ||
97 | Nothing | member (nodeId ni) spill -> bump (probeSpill prober) (nodeAddr ni) | ||
98 | | member (nodeId ni) q -> return () | ||
99 | | otherwise -> bump (probeQueue prober) (nodeAddr ni) | ||
100 | |||
101 | maxSpill :: Int | ||
102 | maxSpill = 100 | ||
103 | |||
104 | maxCache :: Int | ||
105 | maxCache = 50 | ||
106 | |||
107 | runProbeQueue :: TCPProber -> TCP.RelayClient -> Int -> IO () | ||
108 | runProbeQueue prober client maxjobs = do | ||
109 | jcnt <- newTVarIO 0 | ||
110 | fix $ \loop -> do | ||
111 | (tm, mni) <- atomically $ do | ||
112 | j <- readTVar jcnt | ||
113 | check (j < maxjobs) | ||
114 | q <- readTVar $ probeQueue prober | ||
115 | case minView q of | ||
116 | Nothing -> retry | ||
117 | Just (Binding nid saddr tm,q') -> do | ||
118 | writeTVar (probeQueue prober) q' | ||
119 | return (tm, nodeInfo nid saddr) | ||
120 | forM_ mni $ \ni -> do | ||
121 | atomically $ modifyTVar' jcnt succ | ||
122 | t <- forkIO $ do | ||
123 | m <- resolvePort client ni | ||
124 | atomically $ case m of | ||
125 | Nothing -> do | ||
126 | pcnt <- readTVar (probeSpillCount prober) | ||
127 | modifyTVar' (probeSpill prober) $ insert' (nodeId ni) (nodeAddr ni) tm | ||
128 | if (pcnt == maxSpill) | ||
129 | then modifyTVar' (probeSpill prober) deleteMin | ||
130 | else modifyTVar' (probeSpillCount prober) succ | ||
131 | Just p -> do | ||
132 | ccnt <- readTVar (probeCacheCount prober) | ||
133 | modifyTVar' (probeCache prober) $ insert' (nodeId ni) (nodeAddr ni,p) tm | ||
134 | if (ccnt == maxCache) | ||
135 | then modifyTVar' (probeCache prober) deleteMin | ||
136 | else modifyTVar' (probeCacheCount prober) succ | ||
137 | atomically $ modifyTVar' jcnt pred | ||
138 | labelThread t ("probe."++show ni) | ||
139 | loop | ||
140 | |||
141 | getNodes :: TCPProber -> TCP.TCPClient err () Nonce8 -> NodeId -> TCP.NodeInfo -> IO (Maybe ([TCP.NodeInfo],[TCP.NodeInfo],Maybe ())) | ||
142 | getNodes prober tcp seeking dst = do | ||
143 | r <- TCP.getUDPNodes' tcp seeking (TCP.udpNodeInfo dst) | ||
144 | let tcps (ns,_,mb) = (ns',ns',mb) | ||
145 | where ns' = do | ||
146 | n <- ns | ||
147 | [ TCP.NodeInfo n 0 ] | ||
148 | fmap join $ forM r $ \(ns,gw) -> do | ||
149 | let ts = tcps ns | ||
150 | if TCP.nodeId gw == TCP.nodeId dst | ||
151 | then return $ Just ts | ||
152 | else do | ||
153 | enqueueProbe prober (TCP.udpNodeInfo dst) | ||
154 | return $ Just ts | ||
155 | return $ Just ts | ||
156 | |||
157 | nodeSearch :: TCPProber -> TCP.TCPClient err () Nonce8 -> Search NodeId (IP, PortNumber) () TCP.NodeInfo TCP.NodeInfo | ||
158 | nodeSearch prober tcp = Search | ||
159 | { searchSpace = TCP.tcpSpace | ||
160 | , searchNodeAddress = TCP.nodeIP &&& TCP.tcpPort | ||
161 | , searchQuery = getNodes prober tcp | ||
162 | } | ||
diff --git a/examples/dhtd.hs b/examples/dhtd.hs index 959383dc..1223edc8 100644 --- a/examples/dhtd.hs +++ b/examples/dhtd.hs | |||
@@ -97,6 +97,7 @@ import qualified Network.Tox.Onion.Transport as Tox | |||
97 | import qualified Network.Tox.Onion.Handlers as Tox | 97 | import qualified Network.Tox.Onion.Handlers as Tox |
98 | 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 | 99 | import qualified Network.Tox.TCP as TCP |
100 | import qualified TCPProber as TCP | ||
100 | import Data.Typeable | 101 | import Data.Typeable |
101 | import Network.Tox.ContactInfo as Tox | 102 | import Network.Tox.ContactInfo as Tox |
102 | import OnionRouter | 103 | import OnionRouter |
@@ -1490,6 +1491,7 @@ initTox opts ssvar keysdb mbxmpp invc = case porttox opts of | |||
1490 | Want_IP4 -> toxStrap4 | 1491 | Want_IP4 -> toxStrap4 |
1491 | Want_IP6 -> toxStrap6 | 1492 | Want_IP6 -> toxStrap6 |
1492 | } | 1493 | } |
1494 | tcpprober = tcpProber $ Tox.toxOnionRoutes tox | ||
1493 | tcpclient = tcpKademliaClient $ Tox.toxOnionRoutes tox | 1495 | tcpclient = tcpKademliaClient $ Tox.toxOnionRoutes tox |
1494 | tcpRefresher = tcpBucketRefresher $ Tox.toxOnionRoutes tox | 1496 | tcpRefresher = tcpBucketRefresher $ Tox.toxOnionRoutes tox |
1495 | tcpDHT = DHT | 1497 | tcpDHT = DHT |
@@ -1500,9 +1502,9 @@ initTox opts ssvar keysdb mbxmpp invc = case porttox opts of | |||
1500 | , pingShowResult = show | 1502 | , pingShowResult = show |
1501 | } | 1503 | } |
1502 | , dhtQuery = Map.singleton "node" DHTQuery | 1504 | , dhtQuery = Map.singleton "node" DHTQuery |
1503 | { qsearch = TCP.nodeSearch tcpclient | 1505 | { qsearch = TCP.nodeSearch tcpprober tcpclient |
1504 | , qhandler = \ni nid -> do | 1506 | , qhandler = \ni nid -> do |
1505 | ns <- R.kclosest (searchSpace $ TCP.nodeSearch tcpclient) searchK nid | 1507 | ns <- R.kclosest (searchSpace $ TCP.nodeSearch tcpprober tcpclient) searchK nid |
1506 | <$> atomically (readTVar $ refreshBuckets tcpRefresher) | 1508 | <$> atomically (readTVar $ refreshBuckets tcpRefresher) |
1507 | return (ns,ns,Just ()) | 1509 | return (ns,ns,Just ()) |
1508 | , qshowR = show -- TCP.NodeInfo | 1510 | , qshowR = show -- TCP.NodeInfo |
@@ -13,7 +13,7 @@ done | |||
13 | 13 | ||
14 | warn="-freverse-errors -fwarn-unused-imports -Wmissing-signatures -fdefer-typed-holes" | 14 | warn="-freverse-errors -fwarn-unused-imports -Wmissing-signatures -fdefer-typed-holes" |
15 | exts="-XOverloadedStrings -XRecordWildCards" | 15 | exts="-XOverloadedStrings -XRecordWildCards" |
16 | defs="-DBENCODE_AESON -DTHREAD_DEBUG" | 16 | defs="-DBENCODE_AESON -DTHREAD_DEBUG -UVERSION_lens" |
17 | hidden="crypto-random crypto-api crypto-numbers cryptohash prettyclass" | 17 | hidden="crypto-random crypto-api crypto-numbers cryptohash prettyclass" |
18 | [ "$rootname" == "stack" ] && hidden="" | 18 | [ "$rootname" == "stack" ] && hidden="" |
19 | hide="" | 19 | hide="" |
diff --git a/src/Network/Tox.hs b/src/Network/Tox.hs index ea9bbe56..d42f447d 100644 --- a/src/Network/Tox.hs +++ b/src/Network/Tox.hs | |||
@@ -65,6 +65,7 @@ import Network.Tox.ContactInfo | |||
65 | import Text.XXD | 65 | import Text.XXD |
66 | import DPut | 66 | import DPut |
67 | import DebugTag | 67 | import DebugTag |
68 | import TCPProber | ||
68 | import Network.Tox.Avahi | 69 | import Network.Tox.Avahi |
69 | import Network.Tox.Session | 70 | import Network.Tox.Session |
70 | import Network.Tox.Relay | 71 | import Network.Tox.Relay |
@@ -375,6 +376,10 @@ forkTox tox with_avahi = do | |||
375 | quitNC <- forkListener "toxCrypto" (toxCrypto tox) | 376 | quitNC <- forkListener "toxCrypto" (toxCrypto tox) |
376 | quitTCP <- forkListener "relay-client" (clientNet $ tcpClient $ tcpKademliaClient $ toxOnionRoutes tox) | 377 | quitTCP <- forkListener "relay-client" (clientNet $ tcpClient $ tcpKademliaClient $ toxOnionRoutes tox) |
377 | tcpKademlia <- forkPollForRefresh (tcpBucketRefresher $ toxOnionRoutes tox) | 378 | tcpKademlia <- forkPollForRefresh (tcpBucketRefresher $ toxOnionRoutes tox) |
379 | tcpprobe <- forkIO $ runProbeQueue (tcpProber $ toxOnionRoutes tox) | ||
380 | (tcpClient $ tcpKademliaClient $ toxOnionRoutes tox) | ||
381 | 12 | ||
382 | labelThread tcpprobe "tcp-probe" | ||
378 | quitAvahi <- if with_avahi then do | 383 | quitAvahi <- if with_avahi then do |
379 | forkPollForRefresh (DHT.refresher4 $ toxRouting tox) | 384 | forkPollForRefresh (DHT.refresher4 $ toxRouting tox) |
380 | forkPollForRefresh (DHT.refresher6 $ toxRouting tox) | 385 | forkPollForRefresh (DHT.refresher6 $ toxRouting tox) |
@@ -392,6 +397,7 @@ forkTox tox with_avahi = do | |||
392 | quitOnion | 397 | quitOnion |
393 | quitTCP | 398 | quitTCP |
394 | killThread tcpKademlia | 399 | killThread tcpKademlia |
400 | killThread tcpprobe | ||
395 | quitToRoute | 401 | quitToRoute |
396 | quitHs | 402 | quitHs |
397 | , bootstrap (DHT.refresher4 $ toxRouting tox) | 403 | , bootstrap (DHT.refresher4 $ toxRouting tox) |
diff --git a/src/Network/Tox/TCP.hs b/src/Network/Tox/TCP.hs index 48059108..e3f5012b 100644 --- a/src/Network/Tox/TCP.hs +++ b/src/Network/Tox/TCP.hs | |||
@@ -16,6 +16,7 @@ import Data.Functor.Identity | |||
16 | import Data.Hashable | 16 | import Data.Hashable |
17 | import qualified Data.HashMap.Strict as HashMap | 17 | import qualified Data.HashMap.Strict as HashMap |
18 | import Data.IP | 18 | import Data.IP |
19 | import Data.Maybe | ||
19 | import Data.Monoid | 20 | import Data.Monoid |
20 | import Data.Serialize | 21 | import Data.Serialize |
21 | import Data.Word | 22 | import Data.Word |
@@ -24,13 +25,14 @@ import Network.Socket (SockAddr(..)) | |||
24 | import qualified Text.ParserCombinators.ReadP as RP | 25 | import qualified Text.ParserCombinators.ReadP as RP |
25 | import System.IO.Error | 26 | import System.IO.Error |
26 | 27 | ||
28 | import ControlMaybe | ||
27 | import Crypto.Tox | 29 | import Crypto.Tox |
28 | import Data.ByteString (hPut,hGet,ByteString,length) | 30 | import Data.ByteString (hPut,hGet,ByteString,length) |
29 | import Data.Tox.Relay | 31 | import Data.Tox.Relay |
30 | import qualified Data.Word64Map | 32 | import qualified Data.Word64Map |
31 | import DebugTag | 33 | import DebugTag |
32 | import DPut | 34 | import DPut |
33 | import Network.Address (setPort,PortNumber) | 35 | import Network.Address (setPort,PortNumber,localhost4,fromSockAddr) |
34 | import Network.Kademlia.Routing | 36 | import Network.Kademlia.Routing |
35 | import Network.Kademlia.Search hiding (sendQuery) | 37 | import Network.Kademlia.Search hiding (sendQuery) |
36 | import Network.QueryResponse | 38 | import Network.QueryResponse |
@@ -116,7 +118,13 @@ tcpStream crypto = StreamHandshake | |||
116 | dput XTCP $ "TCP:" ++ show addr ++ " <-- " ++ show hello | 118 | dput XTCP $ "TCP:" ++ show addr ++ " <-- " ++ show hello |
117 | hPut h $ encode $ encryptPayload (noncef $ helloNonce hello) hello | 119 | hPut h $ encode $ encryptPayload (noncef $ helloNonce hello) hello |
118 | welcomeE <- withSize $ fmap decode . hGet h . constSize | 120 | welcomeE <- withSize $ fmap decode . hGet h . constSize |
119 | let Right welcome = welcomeE >>= \w -> decryptPayload (noncef $ welcomeNonce w) w | 121 | let mwelcome = welcomeE >>= \w -> decryptPayload (noncef $ welcomeNonce w) w |
122 | nil = SessionProtocol | ||
123 | { streamGoodbye = return () | ||
124 | , streamDecode = return Nothing | ||
125 | , streamEncode = \y -> return () | ||
126 | } | ||
127 | either (\_ -> return nil) id $ mwelcome <&> \welcome -> do | ||
120 | dput XTCP $ "TCP:" ++ show addr ++ " --> " ++ show welcome | 128 | dput XTCP $ "TCP:" ++ show addr ++ " --> " ++ show welcome |
121 | noncef' <- lookupNonceFunction crypto skey (sessionPublicKey $ runIdentity $ welcomeData welcome) | 129 | noncef' <- lookupNonceFunction crypto skey (sessionPublicKey $ runIdentity $ welcomeData welcome) |
122 | nsend <- newMVar (sessionBaseNonce $ runIdentity $ helloData hello) | 130 | nsend <- newMVar (sessionBaseNonce $ runIdentity $ helloData hello) |
@@ -166,12 +174,14 @@ toxTCP crypto = tcpTransport 30 (tcpStream crypto) | |||
166 | tcpSpace :: KademliaSpace NodeId NodeInfo | 174 | tcpSpace :: KademliaSpace NodeId NodeInfo |
167 | tcpSpace = contramap udpNodeInfo toxSpace | 175 | tcpSpace = contramap udpNodeInfo toxSpace |
168 | 176 | ||
177 | {- | ||
169 | nodeSearch :: TCPClient err () Nonce8 -> Search NodeId (IP, PortNumber) () NodeInfo NodeInfo | 178 | nodeSearch :: TCPClient err () Nonce8 -> Search NodeId (IP, PortNumber) () NodeInfo NodeInfo |
170 | nodeSearch tcp = Search | 179 | nodeSearch tcp = Search |
171 | { searchSpace = tcpSpace | 180 | { searchSpace = tcpSpace |
172 | , searchNodeAddress = nodeIP &&& tcpPort | 181 | , searchNodeAddress = nodeIP &&& tcpPort |
173 | , searchQuery = getTCPNodes tcp | 182 | , searchQuery = getNodes tcp |
174 | } | 183 | } |
184 | -} | ||
175 | 185 | ||
176 | data TCPClient err meth tid = TCPClient | 186 | data TCPClient err meth tid = TCPClient |
177 | { tcpCrypto :: TransportCrypto | 187 | { tcpCrypto :: TransportCrypto |
@@ -179,24 +189,44 @@ data TCPClient err meth tid = TCPClient | |||
179 | , tcpGetGateway :: UDP.NodeInfo -> STM (Maybe NodeInfo) | 189 | , tcpGetGateway :: UDP.NodeInfo -> STM (Maybe NodeInfo) |
180 | } | 190 | } |
181 | 191 | ||
192 | {- | ||
182 | getTCPNodes :: TCPClient err () Nonce8 -> NodeId -> NodeInfo -> IO (Maybe ([NodeInfo],[NodeInfo],Maybe ())) | 193 | getTCPNodes :: TCPClient err () Nonce8 -> NodeId -> NodeInfo -> IO (Maybe ([NodeInfo],[NodeInfo],Maybe ())) |
183 | getTCPNodes tcp seeking dst = do | 194 | getTCPNodes tcp seeking dst = do |
184 | r <- getUDPNodes tcp seeking (udpNodeInfo dst) | 195 | r <- getUDPNodes' tcp seeking (udpNodeInfo dst) |
185 | let tcps (ns,_,mb) = (ns',ns',mb) | 196 | let tcps (ns,_,mb) = (ns',ns',mb) |
186 | where ns' = do | 197 | where ns' = do |
187 | n <- ns | 198 | n <- ns |
188 | [ NodeInfo n (fromIntegral 443) , NodeInfo n (fromIntegral 80) , NodeInfo n (UDP.nodePort n) ] | 199 | [ NodeInfo n (fromIntegral 443) , NodeInfo n (fromIntegral 80) , NodeInfo n (UDP.nodePort n) ] |
189 | return $ tcps <$> r | 200 | fmap join $ forM r $ \(ns,gw) -> do |
201 | let ts = tcps ns | ||
202 | {- | ||
203 | if nodeId gw == nodeId dst | ||
204 | then return $ Just ts | ||
205 | else do | ||
206 | forkIO $ void $ tcpPing (tcpClient tcp) dst | ||
207 | return $ Just ts | ||
208 | -} | ||
209 | forM_ ((\(xs,_,_) -> xs) ts) (forkIO . void . tcpPing (tcpClient tcp)) | ||
210 | return $ Just ts | ||
211 | -} | ||
190 | 212 | ||
191 | getUDPNodes :: TCPClient err () Nonce8 -> NodeId -> UDP.NodeInfo -> IO (Maybe ([UDP.NodeInfo], [UDP.NodeInfo], Maybe ())) | 213 | getUDPNodes :: TCPClient err () Nonce8 -> NodeId -> UDP.NodeInfo -> IO (Maybe ([UDP.NodeInfo], [UDP.NodeInfo], Maybe ())) |
192 | getUDPNodes tcp seeking dst = do | 214 | getUDPNodes tcp seeking dst = fmap fst <$> getUDPNodes' tcp seeking dst |
193 | mgateway <- atomically $ tcpGetGateway tcp dst | 215 | |
216 | getUDPNodes' :: TCPClient err () Nonce8 -> NodeId -> UDP.NodeInfo -> IO (Maybe (([UDP.NodeInfo], [UDP.NodeInfo], Maybe ()), NodeInfo)) | ||
217 | getUDPNodes' tcp seeking dst0 = do | ||
218 | mgateway <- atomically $ tcpGetGateway tcp dst0 | ||
194 | fmap join $ forM mgateway $ \gateway -> do | 219 | fmap join $ forM mgateway $ \gateway -> do |
195 | (b,c,n24) <- atomically $ do | 220 | (b,c,n24) <- atomically $ do |
196 | b <- transportNewKey (tcpCrypto tcp) | 221 | b <- transportNewKey (tcpCrypto tcp) |
197 | c <- transportNewKey (tcpCrypto tcp) | 222 | c <- transportNewKey (tcpCrypto tcp) |
198 | n24 <- transportNewNonce (tcpCrypto tcp) | 223 | n24 <- transportNewNonce (tcpCrypto tcp) |
199 | return (b,c,n24) | 224 | return (b,c,n24) |
225 | let (dst,gateway') = if UDP.nodeId dst0 == nodeId gateway | ||
226 | then ( dst0 { UDP.nodeIP = fromJust $ fromSockAddr localhost4 } | ||
227 | , gateway { udpNodeInfo = (udpNodeInfo gateway) | ||
228 | { UDP.nodeIP = fromJust $ fromSockAddr localhost4 }}) | ||
229 | else (dst0,gateway) | ||
200 | wrap2 <- lookupNonceFunction (tcpCrypto tcp) b (UDP.id2key $ UDP.nodeId dst) | 230 | wrap2 <- lookupNonceFunction (tcpCrypto tcp) b (UDP.id2key $ UDP.nodeId dst) |
201 | wrap1 <- lookupNonceFunction (tcpCrypto tcp) c (UDP.id2key $ nodeId gateway) | 231 | wrap1 <- lookupNonceFunction (tcpCrypto tcp) c (UDP.id2key $ nodeId gateway) |
202 | wrap0 <- lookupNonceFunction (tcpCrypto tcp) (transportSecret $ tcpCrypto tcp) (UDP.id2key $ UDP.nodeId dst) | 232 | wrap0 <- lookupNonceFunction (tcpCrypto tcp) (transportSecret $ tcpCrypto tcp) (UDP.id2key $ UDP.nodeId dst) |
@@ -205,7 +235,7 @@ getUDPNodes tcp seeking dst = do | |||
205 | , method = () -- meth | 235 | , method = () -- meth |
206 | , wrapQuery = \n8 src gateway x -> | 236 | , wrapQuery = \n8 src gateway x -> |
207 | OnionPacket n24 $ Addressed (UDP.nodeAddr dst) | 237 | OnionPacket n24 $ Addressed (UDP.nodeAddr dst) |
208 | $ wrapOnionPure b (wrap2 n24) (nodeAddr gateway) | 238 | $ wrapOnionPure b (wrap2 n24) (nodeAddr gateway') |
209 | $ wrapOnionPure c (wrap1 n24) (UDP.nodeAddr dst) | 239 | $ wrapOnionPure c (wrap1 n24) (UDP.nodeAddr dst) |
210 | $ NotForwarded $ encryptPayload (wrap0 n24) | 240 | $ NotForwarded $ encryptPayload (wrap0 n24) |
211 | $ OnionAnnounce Asymm | 241 | $ OnionAnnounce Asymm |
@@ -221,7 +251,7 @@ getUDPNodes tcp seeking dst = do | |||
221 | r <- sendQuery (tcpClient tcp) meth (AnnounceRequest zeros32 seeking UDP.zeroID) gateway | 251 | r <- sendQuery (tcpClient tcp) meth (AnnounceRequest zeros32 seeking UDP.zeroID) gateway |
222 | forM r $ \response -> do | 252 | forM r $ \response -> do |
223 | let (ns,_,mb) = either (const ([],[],Nothing)) (unwrapAnnounceResponse Nothing dst) $ response | 253 | let (ns,_,mb) = either (const ([],[],Nothing)) (unwrapAnnounceResponse Nothing dst) $ response |
224 | return (ns,ns, const () <$> mb) | 254 | return ( (ns,ns, const () <$> mb), gateway ) |
225 | 255 | ||
226 | 256 | ||
227 | handleOOB :: PublicKey -> ByteString -> NodeInfo -> NodeInfo -> IO (Maybe (RelayPacket -> RelayPacket)) | 257 | handleOOB :: PublicKey -> ByteString -> NodeInfo -> NodeInfo -> IO (Maybe (RelayPacket -> RelayPacket)) |
@@ -243,7 +273,9 @@ tcpPing client dst = sendQuery client meth () dst | |||
243 | , method = () | 273 | , method = () |
244 | } | 274 | } |
245 | 275 | ||
246 | newClient :: TransportCrypto -> IO (Client String () Nonce8 NodeInfo RelayPacket) | 276 | type RelayClient = Client String () Nonce8 NodeInfo RelayPacket |
277 | |||
278 | newClient :: TransportCrypto -> IO RelayClient | ||
247 | newClient crypto = do | 279 | newClient crypto = do |
248 | net <- toxTCP crypto | 280 | net <- toxTCP crypto |
249 | drg <- drgNew | 281 | drg <- drgNew |