summaryrefslogtreecommitdiff
path: root/src/Network/Tox/TCP.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/Tox/TCP.hs')
-rw-r--r--src/Network/Tox/TCP.hs85
1 files changed, 85 insertions, 0 deletions
diff --git a/src/Network/Tox/TCP.hs b/src/Network/Tox/TCP.hs
new file mode 100644
index 00000000..0780f121
--- /dev/null
+++ b/src/Network/Tox/TCP.hs
@@ -0,0 +1,85 @@
1{-# LANGUAGE RecursiveDo #-}
2{-# LANGUAGE PartialTypeSignatures #-}
3{-# LANGUAGE LambdaCase #-}
4{-# LANGUAGE FlexibleContexts #-}
5module Network.Tox.TCP where
6
7import Control.Concurrent
8import Control.Concurrent.STM
9import Data.Functor.Identity
10import Data.Serialize
11import System.IO (Handle)
12
13import Crypto.Tox
14import Data.ByteString (hPut,hGet,ByteString)
15import Data.Tox.Relay
16import Network.Address (setPort,PortNumber,SockAddr)
17import Network.QueryResponse
18import Network.QueryResponse.TCP
19import qualified Network.Tox.NodeId as UDP
20
21
22withSize :: Sized x => (Size x -> m (p x)) -> m (p x)
23withSize f = case size of len -> f len
24
25data NodeInfo = NodeInfo
26 { udpNodeInfo :: UDP.NodeInfo
27 , tcpPort :: PortNumber
28 }
29
30type NodeId = UDP.NodeId
31
32nodeId :: NodeInfo -> NodeId
33nodeId ni = UDP.nodeId $ udpNodeInfo ni
34
35nodeAddr :: NodeInfo -> SockAddr
36nodeAddr ni = setPort (tcpPort ni) $ UDP.nodeAddr $ udpNodeInfo ni
37
38tcpStream :: (Serialize y, Sized y, Serialize x, Sized x) =>
39 TransportCrypto -> StreamHandshake NodeInfo x y
40tcpStream crypto = StreamHandshake
41 { streamHello = \addr h -> do
42 (skey, hello) <- atomically $ do
43 n24 <- transportNewNonce crypto
44 skey <- transportNewKey crypto
45 base24 <- transportNewNonce crypto
46 return $ (,) skey $ Hello $ Asymm
47 { senderKey = transportPublic crypto
48 , asymmNonce = n24
49 , asymmData = pure HelloData
50 { sessionPublicKey = toPublic $ skey
51 , sessionBaseNonce = base24
52 }
53 }
54 noncef <- lookupNonceFunction crypto (transportSecret crypto) (UDP.id2key $ nodeId addr)
55 hPut h $ encode $ encryptPayload (noncef $ helloNonce hello) hello
56 welcomeE <- withSize $ fmap decode . hGet h . constSize
57 let Right welcome = welcomeE >>= \w -> decryptPayload (noncef $ welcomeNonce w) w
58 noncef' <- lookupNonceFunction crypto skey (sessionPublicKey $ runIdentity $ welcomeData welcome)
59 nsend <- newMVar (sessionBaseNonce $ runIdentity $ helloData hello)
60 nread <- newMVar (sessionBaseNonce $ runIdentity $ welcomeData welcome)
61 let them = sessionPublicKey $ runIdentity $ welcomeData welcome
62 return SessionProtocol
63 { streamGoodbye = \h -> return () -- No goodbye packet? Seems rude.
64 , streamDecode = \h -> do
65 decode <$> hGet h 2 >>= \case
66 Left _ -> return Nothing
67 Right len -> do
68 decode <$> hGet h len >>= \case
69 Left _ -> return Nothing
70 Right x -> do
71 n24 <- takeMVar nread
72 let r = decrypt (noncef' n24) x >>= decodePlain
73 putMVar nread (incrementNonce24 n24)
74 return $ either (const Nothing) Just r
75 , streamEncode = \y -> do
76 n24 <- takeMVar nsend
77 let bs = encode $ encrypt (noncef' n24) $ encodePlain y
78 putMVar nsend (incrementNonce24 n24)
79 return bs -- XXX: Should we wait until this bytestring is sent before putting the nonce back in the MVar?
80 }
81 , streamAddr = nodeAddr
82 }
83
84toxTCP :: TransportCrypto -> IO (Transport err NodeInfo RelayPacket)
85toxTCP crypto = tcpTransport 30 (tcpStream crypto)