summaryrefslogtreecommitdiff
path: root/dht/src/Network/Tox/TCP.hs
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2019-12-14 16:11:03 -0500
committerJoe Crayne <joe@jerkface.net>2020-01-01 23:26:49 -0500
commitd5efdc327bbb69a905043df45415817e318e38ee (patch)
tree7be975048f3e40c27811bdb39ba92d871a42588c /dht/src/Network/Tox/TCP.hs
parent8c04d9cca70241bebe4b94b779fe7bbfe6140f51 (diff)
Multi Transports: TCP for DHT/Cookies/Handshakes.
Diffstat (limited to 'dht/src/Network/Tox/TCP.hs')
-rw-r--r--dht/src/Network/Tox/TCP.hs80
1 files changed, 66 insertions, 14 deletions
diff --git a/dht/src/Network/Tox/TCP.hs b/dht/src/Network/Tox/TCP.hs
index 4b3a4594..dc4c9967 100644
--- a/dht/src/Network/Tox/TCP.hs
+++ b/dht/src/Network/Tox/TCP.hs
@@ -21,6 +21,7 @@ import Data.Functor.Contravariant
21import Data.Functor.Identity 21import Data.Functor.Identity
22import Data.Hashable 22import Data.Hashable
23import qualified Data.HashMap.Strict as HashMap 23import qualified Data.HashMap.Strict as HashMap
24import qualified Data.IntMap.Strict as IntMap
24import Data.IP 25import Data.IP
25import Data.Maybe 26import Data.Maybe
26import Data.Monoid 27import Data.Monoid
@@ -48,9 +49,9 @@ import Network.Kademlia.Search hiding (sendQuery)
48import Network.QueryResponse 49import Network.QueryResponse
49import Network.QueryResponse.TCP 50import Network.QueryResponse.TCP
50import Network.Tox.TCP.NodeId () 51import Network.Tox.TCP.NodeId ()
51import Network.Tox.DHT.Handlers (toxSpace) 52import Network.Tox.DHT.Transport (toxSpace)
52import Network.Tox.Onion.Transport hiding (encrypt,decrypt) 53import Network.Tox.Onion.Transport hiding (encrypt,decrypt)
53import Network.Tox.Onion.Handlers (unwrapAnnounceResponse) 54import Network.Tox.Onion.Transport (unwrapAnnounceResponse)
54import qualified Network.Tox.NodeId as UDP 55import qualified Network.Tox.NodeId as UDP
55import Text.XXD 56import Text.XXD
56import Data.Proxy 57import Data.Proxy
@@ -72,8 +73,8 @@ nodeIP :: NodeInfo -> IP
72nodeIP ni = UDP.nodeIP $ udpNodeInfo ni 73nodeIP ni = UDP.nodeIP $ udpNodeInfo ni
73 74
74tcpStream :: (Show y, Show x, Serialize y, Sized y, Serialize x, Sized x) => 75tcpStream :: (Show y, Show x, Serialize y, Sized y, Serialize x, Sized x) =>
75 TransportCrypto -> StreamHandshake NodeInfo x y 76 TransportCrypto -> (NodeInfo -> IO st) -> StreamHandshake NodeInfo (st,x) y
76tcpStream crypto = StreamHandshake 77tcpStream crypto mkst = StreamHandshake
77 { streamHello = \addr h -> do 78 { streamHello = \addr h -> do
78 (skey, hello) <- atomically $ do 79 (skey, hello) <- atomically $ do
79 n24 <- transportNewNonce crypto 80 n24 <- transportNewNonce crypto
@@ -113,6 +114,7 @@ tcpStream crypto = StreamHandshake
113 nread <- newMVar (sessionBaseNonce $ runIdentity $ welcomeData welcome) 114 nread <- newMVar (sessionBaseNonce $ runIdentity $ welcomeData welcome)
114 let them = sessionPublicKey $ runIdentity $ welcomeData welcome 115 let them = sessionPublicKey $ runIdentity $ welcomeData welcome
115 hvar <- newMVar h 116 hvar <- newMVar h
117 st <- mkst addr
116 return SessionProtocol 118 return SessionProtocol
117 { streamGoodbye = do 119 { streamGoodbye = do
118 dput XTCP $ "Closing " ++ show addr 120 dput XTCP $ "Closing " ++ show addr
@@ -138,7 +140,7 @@ tcpStream crypto = StreamHandshake
138 dput XTCP $ "TCP:" ++ show addr ++ " --> " ++ show x' 140 dput XTCP $ "TCP:" ++ show addr ++ " --> " ++ show x'
139 return ()) 141 return ())
140 r 142 r
141 return $ either (const Nothing) Just r 143 return $ either (const Nothing) (Just . (,) st) r
142 in bracket (takeMVar hvar) (putMVar hvar) 144 in bracket (takeMVar hvar) (putMVar hvar)
143 $ \h -> go h `catchIOError` \e -> do 145 $ \h -> go h `catchIOError` \e -> do
144 dput XTCP $ "TCP exception: " ++ show e 146 dput XTCP $ "TCP exception: " ++ show e
@@ -158,9 +160,26 @@ tcpStream crypto = StreamHandshake
158 , streamAddr = nodeAddr 160 , streamAddr = nodeAddr
159 } 161 }
160 162
161toxTCP :: TransportCrypto -> IO ( TCPCache (SessionProtocol RelayPacket RelayPacket) 163newtype SessionData = SessionData (MVar (IntMap.IntMap NodeId))
162 , TransportA err NodeInfo RelayPacket (Bool,RelayPacket) ) 164
163toxTCP crypto = tcpTransport 30 (tcpStream crypto) 165newSessionData :: NodeInfo -> IO SessionData
166newSessionData _ = SessionData <$> newMVar IntMap.empty
167
168getRelayedRemote :: SessionData -> ConId -> IO NodeId
169getRelayedRemote (SessionData keymapVar) (ConId i) = do
170 keymap <- takeMVar keymapVar
171 let k = fromMaybe UDP.zeroID $ IntMap.lookup (fromIntegral i) keymap
172 putMVar keymapVar keymap
173 return k
174
175setRelayedRemote :: SessionData -> ConId -> NodeId -> IO ()
176setRelayedRemote (SessionData keymapVar) (ConId conid) nid = do
177 keymap <- takeMVar keymapVar
178 putMVar keymapVar $ IntMap.insert (fromIntegral conid) nid keymap
179
180toxTCP :: TransportCrypto -> IO ( TCPCache (SessionProtocol (SessionData,RelayPacket) RelayPacket)
181 , TransportA err NodeInfo (SessionData,RelayPacket) (Bool,RelayPacket) )
182toxTCP crypto = tcpTransport 30 (tcpStream crypto newSessionData)
164 183
165tcpSpace :: KademliaSpace NodeId NodeInfo 184tcpSpace :: KademliaSpace NodeId NodeInfo
166tcpSpace = contramap udpNodeInfo toxSpace 185tcpSpace = contramap udpNodeInfo toxSpace
@@ -292,6 +311,8 @@ keyToNonce k = unsafeDupablePerformIO $ withByteArray k $ \ptr -> do
292 w8 <- peek ptr 311 w8 <- peek ptr
293 return $ Nonce8 w8 312 return $ Nonce8 w8
294 313
314type RelayCache = TCPCache (SessionProtocol (SessionData,RelayPacket) RelayPacket)
315
295-- | Create a new TCP relay client. Because polymorphic existential record 316-- | Create a new TCP relay client. Because polymorphic existential record
296-- updates are currently hard with GHC, this function accepts parameters for 317-- updates are currently hard with GHC, this function accepts parameters for
297-- generalizing the table-entry type for pending transactions. Safe trivial 318-- generalizing the table-entry type for pending transactions. Safe trivial
@@ -301,14 +322,18 @@ newClient :: TransportCrypto
301 -> ((Maybe (Bool,RelayPacket) -> IO ()) -> a) -- ^ store mvar for query 322 -> ((Maybe (Bool,RelayPacket) -> IO ()) -> a) -- ^ store mvar for query
302 -> (a -> RelayPacket -> IO void) -- ^ load mvar for query 323 -> (a -> RelayPacket -> IO void) -- ^ load mvar for query
303 -> IO ( ( TVar (ChaChaDRG, Data.Word64Map.Word64Map a) 324 -> IO ( ( TVar (ChaChaDRG, Data.Word64Map.Word64Map a)
304 , TCPCache (SessionProtocol RelayPacket RelayPacket) ) 325 , RelayCache
326 , Transport String ViaRelay ByteString )
305 , Client String PacketNumber Nonce8 NodeInfo (Bool,RelayPacket)) 327 , Client String PacketNumber Nonce8 NodeInfo (Bool,RelayPacket))
306newClient crypto store load = do 328newClient crypto store load = do
307 (tcpcache,net) <- toxTCP crypto 329 (tcpcache,net0) <- toxTCP crypto
330 (relaynet,net1) <- partitionRelay net0
331 let net2 = {- XXX: Client type forces this pointless layering. -}
332 layerTransport ((Right .) . (,) . (,) False . snd) (,) net1
308 drg <- drgNew 333 drg <- drgNew
309 map_var <- atomically $ newTVar (drg, Data.Word64Map.empty) 334 map_var <- atomically $ newTVar (drg, Data.Word64Map.empty)
310 return $ (,) (map_var,tcpcache) Client 335 return $ (,) (map_var,tcpcache,relaynet) Client
311 { clientNet = {- XXX: Client type forces this pointless layering. -} layerTransport ((Right .) . (,) . (,) False) (,) net 336 { clientNet = net2
312 , clientDispatcher = DispatchMethods 337 , clientDispatcher = DispatchMethods
313 { classifyInbound = (. snd) $ \case 338 { classifyInbound = (. snd) $ \case
314 RelayPing n -> IsQuery PingPacket n 339 RelayPing n -> IsQuery PingPacket n
@@ -318,7 +343,7 @@ newClient crypto store load = do
318 OnionPacketResponse (OnionAnnounceResponse n8 n24 ciphered) -> IsResponse n8 343 OnionPacketResponse (OnionAnnounceResponse n8 n24 ciphered) -> IsResponse n8
319 OnionPacketResponse o@(OnionToRouteResponse _) -> IsUnsolicited $ handle2route o 344 OnionPacketResponse o@(OnionToRouteResponse _) -> IsUnsolicited $ handle2route o
320 OOBRecv k bs -> IsUnsolicited $ handleOOB k bs 345 OOBRecv k bs -> IsUnsolicited $ handleOOB k bs
321 wut -> IsUnknown (show wut) 346 wut -> IsUnknown (show wut)
322 , lookupHandler = \case 347 , lookupHandler = \case
323 PingPacket -> trace ("tcp-received-ping") $ Just MethodHandler 348 PingPacket -> trace ("tcp-received-ping") $ Just MethodHandler
324 { methodParse = \case (_,RelayPing n8) -> Right () 349 { methodParse = \case (_,RelayPing n8) -> Right ()
@@ -330,7 +355,10 @@ newClient crypto store load = do
330 { methodParse = \x -> Left "tcp-lookuphandler?" -- :: x -> Either err a 355 { methodParse = \x -> Left "tcp-lookuphandler?" -- :: x -> Either err a
331 , noreplyAction = \addr a -> dput XTCP $ "tcp-lookupHandler: "++show w 356 , noreplyAction = \addr a -> dput XTCP $ "tcp-lookupHandler: "++show w
332 } 357 }
333 , tableMethods = transactionMethods' store (\x -> mapM_ (load x . snd)) (contramap (\(Nonce8 w64) -> w64) w64MapMethods) 358 , tableMethods = transactionMethods'
359 store
360 (\x -> mapM_ (load x . snd))
361 (contramap (\(Nonce8 w64) -> w64) w64MapMethods)
334 $ first (either error Nonce8 . decode) . randomBytesGenerate 8 362 $ first (either error Nonce8 . decode) . randomBytesGenerate 8
335 } 363 }
336 , clientErrorReporter = logErrors 364 , clientErrorReporter = logErrors
@@ -341,3 +369,27 @@ newClient crypto store load = do
341 } 369 }
342 , clientResponseId = return 370 , clientResponseId = return
343 } 371 }
372
373data ViaRelay = ViaRelay (Maybe ConId) UDP.NodeId NodeInfo
374 deriving (Eq,Ord,Show)
375
376partitionRelay :: TransportA err NodeInfo (SessionData,RelayPacket) (Bool,RelayPacket)
377 -> IO ( Transport err ViaRelay ByteString
378 , TransportA err NodeInfo (SessionData,RelayPacket) (Bool,RelayPacket))
379partitionRelay tr = partitionTransportM parse encode tr
380 where
381 parse :: ((SessionData,RelayPacket), NodeInfo) -> IO (Either (ByteString, ViaRelay) ((SessionData,RelayPacket),NodeInfo))
382 parse ((st,RelayData bs conid), ni) = do
383 nid <- getRelayedRemote st conid
384 return $ Left (bs, ViaRelay (Just conid) nid ni)
385 parse ((_,OOBRecv key bs), ni) =
386 return $ Left (bs, ViaRelay Nothing (UDP.key2id key) ni)
387 parse passthrough@((st,RoutingResponse conid k),ni) = do
388 setRelayedRemote st conid (UDP.key2id k)
389 return $ Right passthrough
390 parse passthrough =
391 return $ Right passthrough
392
393 encode :: (ByteString, ViaRelay) -> IO (Maybe ((Bool,RelayPacket), NodeInfo))
394 encode (bs, ViaRelay (Just conid) _ ni) = return $ Just ((False,RelayData bs conid), ni)
395 encode (bs, ViaRelay Nothing nid ni) = return $ Just ((False,OOBSend (UDP.id2key nid) bs), ni)