diff options
author | Joe Crayne <joe@jerkface.net> | 2019-12-14 16:11:03 -0500 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2020-01-01 23:26:49 -0500 |
commit | d5efdc327bbb69a905043df45415817e318e38ee (patch) | |
tree | 7be975048f3e40c27811bdb39ba92d871a42588c /dht/src/Network/Tox/TCP.hs | |
parent | 8c04d9cca70241bebe4b94b779fe7bbfe6140f51 (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.hs | 80 |
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 | |||
21 | import Data.Functor.Identity | 21 | import Data.Functor.Identity |
22 | import Data.Hashable | 22 | import Data.Hashable |
23 | import qualified Data.HashMap.Strict as HashMap | 23 | import qualified Data.HashMap.Strict as HashMap |
24 | import qualified Data.IntMap.Strict as IntMap | ||
24 | import Data.IP | 25 | import Data.IP |
25 | import Data.Maybe | 26 | import Data.Maybe |
26 | import Data.Monoid | 27 | import Data.Monoid |
@@ -48,9 +49,9 @@ import Network.Kademlia.Search hiding (sendQuery) | |||
48 | import Network.QueryResponse | 49 | import Network.QueryResponse |
49 | import Network.QueryResponse.TCP | 50 | import Network.QueryResponse.TCP |
50 | import Network.Tox.TCP.NodeId () | 51 | import Network.Tox.TCP.NodeId () |
51 | import Network.Tox.DHT.Handlers (toxSpace) | 52 | import Network.Tox.DHT.Transport (toxSpace) |
52 | import Network.Tox.Onion.Transport hiding (encrypt,decrypt) | 53 | import Network.Tox.Onion.Transport hiding (encrypt,decrypt) |
53 | import Network.Tox.Onion.Handlers (unwrapAnnounceResponse) | 54 | import Network.Tox.Onion.Transport (unwrapAnnounceResponse) |
54 | import qualified Network.Tox.NodeId as UDP | 55 | import qualified Network.Tox.NodeId as UDP |
55 | import Text.XXD | 56 | import Text.XXD |
56 | import Data.Proxy | 57 | import Data.Proxy |
@@ -72,8 +73,8 @@ nodeIP :: NodeInfo -> IP | |||
72 | nodeIP ni = UDP.nodeIP $ udpNodeInfo ni | 73 | nodeIP ni = UDP.nodeIP $ udpNodeInfo ni |
73 | 74 | ||
74 | tcpStream :: (Show y, Show x, Serialize y, Sized y, Serialize x, Sized x) => | 75 | tcpStream :: (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 |
76 | tcpStream crypto = StreamHandshake | 77 | tcpStream 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 | ||
161 | toxTCP :: TransportCrypto -> IO ( TCPCache (SessionProtocol RelayPacket RelayPacket) | 163 | newtype SessionData = SessionData (MVar (IntMap.IntMap NodeId)) |
162 | , TransportA err NodeInfo RelayPacket (Bool,RelayPacket) ) | 164 | |
163 | toxTCP crypto = tcpTransport 30 (tcpStream crypto) | 165 | newSessionData :: NodeInfo -> IO SessionData |
166 | newSessionData _ = SessionData <$> newMVar IntMap.empty | ||
167 | |||
168 | getRelayedRemote :: SessionData -> ConId -> IO NodeId | ||
169 | getRelayedRemote (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 | |||
175 | setRelayedRemote :: SessionData -> ConId -> NodeId -> IO () | ||
176 | setRelayedRemote (SessionData keymapVar) (ConId conid) nid = do | ||
177 | keymap <- takeMVar keymapVar | ||
178 | putMVar keymapVar $ IntMap.insert (fromIntegral conid) nid keymap | ||
179 | |||
180 | toxTCP :: TransportCrypto -> IO ( TCPCache (SessionProtocol (SessionData,RelayPacket) RelayPacket) | ||
181 | , TransportA err NodeInfo (SessionData,RelayPacket) (Bool,RelayPacket) ) | ||
182 | toxTCP crypto = tcpTransport 30 (tcpStream crypto newSessionData) | ||
164 | 183 | ||
165 | tcpSpace :: KademliaSpace NodeId NodeInfo | 184 | tcpSpace :: KademliaSpace NodeId NodeInfo |
166 | tcpSpace = contramap udpNodeInfo toxSpace | 185 | tcpSpace = 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 | ||
314 | type 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)) |
306 | newClient crypto store load = do | 328 | newClient 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 | |||
373 | data ViaRelay = ViaRelay (Maybe ConId) UDP.NodeId NodeInfo | ||
374 | deriving (Eq,Ord,Show) | ||
375 | |||
376 | partitionRelay :: TransportA err NodeInfo (SessionData,RelayPacket) (Bool,RelayPacket) | ||
377 | -> IO ( Transport err ViaRelay ByteString | ||
378 | , TransportA err NodeInfo (SessionData,RelayPacket) (Bool,RelayPacket)) | ||
379 | partitionRelay 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) | ||