diff options
Diffstat (limited to 'src/Network/Tox/TCP.hs')
-rw-r--r-- | src/Network/Tox/TCP.hs | 76 |
1 files changed, 43 insertions, 33 deletions
diff --git a/src/Network/Tox/TCP.hs b/src/Network/Tox/TCP.hs index a7881c24..71050fe8 100644 --- a/src/Network/Tox/TCP.hs +++ b/src/Network/Tox/TCP.hs | |||
@@ -7,6 +7,7 @@ module Network.Tox.TCP | |||
7 | , NodeInfo(..) | 7 | , NodeInfo(..) |
8 | ) where | 8 | ) where |
9 | 9 | ||
10 | import Debug.Trace | ||
10 | import Control.Arrow | 11 | import Control.Arrow |
11 | import Control.Concurrent | 12 | import Control.Concurrent |
12 | import Control.Concurrent.STM | 13 | import Control.Concurrent.STM |
@@ -27,6 +28,7 @@ import qualified Data.Vector as Vector | |||
27 | import Network.Socket (SockAddr(..)) | 28 | import Network.Socket (SockAddr(..)) |
28 | import qualified Text.ParserCombinators.ReadP as RP | 29 | import qualified Text.ParserCombinators.ReadP as RP |
29 | import System.IO.Error | 30 | import System.IO.Error |
31 | import System.Timeout | ||
30 | 32 | ||
31 | import ControlMaybe | 33 | import ControlMaybe |
32 | import Crypto.Tox | 34 | import Crypto.Tox |
@@ -113,15 +115,16 @@ tcpStream crypto = StreamHandshake | |||
113 | dput XTCP $ "TCP: Failed to decode packet." | 115 | dput XTCP $ "TCP: Failed to decode packet." |
114 | return Nothing | 116 | return Nothing |
115 | Right x -> do | 117 | Right x -> do |
116 | n24 <- takeMVar nread | 118 | m24 <- timeout 100000 (takeMVar nread) |
117 | let r = decrypt (noncef' n24) x >>= decodePlain | 119 | fmap join $ forM m24 $ \n24 -> do |
118 | putMVar nread (incrementNonce24 n24) | 120 | let r = decrypt (noncef' n24) x >>= decodePlain |
119 | either (dput XTCP) | 121 | putMVar nread (incrementNonce24 n24) |
120 | (\x' -> do | 122 | either (dput XTCP) |
121 | dput XTCP $ "TCP:" ++ show addr ++ " --> " ++ show x' | 123 | (\x' -> do |
122 | return ()) | 124 | dput XTCP $ "TCP:" ++ show addr ++ " --> " ++ show x' |
123 | r | 125 | return ()) |
124 | return $ either (const Nothing) Just r | 126 | r |
127 | return $ either (const Nothing) Just r | ||
125 | in go `catchIOError` \e -> do | 128 | in go `catchIOError` \e -> do |
126 | dput XTCP $ "TCP exception: " ++ show e | 129 | dput XTCP $ "TCP exception: " ++ show e |
127 | return Nothing | 130 | return Nothing |
@@ -129,14 +132,14 @@ tcpStream crypto = StreamHandshake | |||
129 | n24 <- takeMVar nsend | 132 | n24 <- takeMVar nsend |
130 | dput XTCP $ "TCP:" ++ show addr ++ " <-- " ++ show y | 133 | dput XTCP $ "TCP:" ++ show addr ++ " <-- " ++ show y |
131 | let bs = encode $ encrypt (noncef' n24) $ encodePlain y | 134 | let bs = encode $ encrypt (noncef' n24) $ encodePlain y |
132 | hPut h $ encode (fromIntegral $ Data.ByteString.length bs :: Word16) | 135 | hPut h (encode (fromIntegral $ Data.ByteString.length bs :: Word16) <> bs) |
133 | <> bs | 136 | `catchIOError` \e -> dput XTCP $ "TCP write exception: " ++ show e |
134 | putMVar nsend (incrementNonce24 n24) | 137 | putMVar nsend (incrementNonce24 n24) |
135 | } | 138 | } |
136 | , streamAddr = nodeAddr | 139 | , streamAddr = nodeAddr |
137 | } | 140 | } |
138 | 141 | ||
139 | toxTCP :: TransportCrypto -> IO (Transport err NodeInfo RelayPacket) | 142 | toxTCP :: TransportCrypto -> IO (TransportA err NodeInfo RelayPacket (Bool,RelayPacket)) |
140 | toxTCP crypto = tcpTransport 30 (tcpStream crypto) | 143 | toxTCP crypto = tcpTransport 30 (tcpStream crypto) |
141 | 144 | ||
142 | tcpSpace :: KademliaSpace NodeId NodeInfo | 145 | tcpSpace :: KademliaSpace NodeId NodeInfo |
@@ -153,7 +156,7 @@ nodeSearch tcp = Search | |||
153 | 156 | ||
154 | data TCPClient err meth tid = TCPClient | 157 | data TCPClient err meth tid = TCPClient |
155 | { tcpCrypto :: TransportCrypto | 158 | { tcpCrypto :: TransportCrypto |
156 | , tcpClient :: Client err () tid NodeInfo RelayPacket | 159 | , tcpClient :: Client err PacketNumber tid NodeInfo (Bool,RelayPacket) |
157 | , tcpGetGateway :: UDP.NodeInfo -> STM (Maybe NodeInfo) | 160 | , tcpGetGateway :: UDP.NodeInfo -> STM (Maybe NodeInfo) |
158 | } | 161 | } |
159 | 162 | ||
@@ -200,8 +203,8 @@ getUDPNodes' tcp seeking dst0 = do | |||
200 | wrap0 <- lookupNonceFunction (tcpCrypto tcp) (transportSecret $ tcpCrypto tcp) (UDP.id2key $ UDP.nodeId dst) | 203 | wrap0 <- lookupNonceFunction (tcpCrypto tcp) (transportSecret $ tcpCrypto tcp) (UDP.id2key $ UDP.nodeId dst) |
201 | let meth = MethodSerializer -- MethodSerializer Nonce8 NodeInfo RelayPacket meth AnnounceRequest (Either String AnnounceResponse) | 204 | let meth = MethodSerializer -- MethodSerializer Nonce8 NodeInfo RelayPacket meth AnnounceRequest (Either String AnnounceResponse) |
202 | { methodTimeout = \tid addr -> return (addr,12000000) -- 12 second timeout | 205 | { methodTimeout = \tid addr -> return (addr,12000000) -- 12 second timeout |
203 | , method = () -- meth | 206 | , method = OnionPacketID -- meth |
204 | , wrapQuery = \n8 src gateway x -> | 207 | , wrapQuery = \n8 src gateway x -> (,) True $ |
205 | OnionPacket n24 $ Addressed (UDP.nodeAddr dst) | 208 | OnionPacket n24 $ Addressed (UDP.nodeAddr dst) |
206 | $ wrapOnionPure b (wrap2 n24) (nodeAddr gateway') | 209 | $ wrapOnionPure b (wrap2 n24) (nodeAddr gateway') |
207 | $ wrapOnionPure c (wrap1 n24) (UDP.nodeAddr dst) | 210 | $ wrapOnionPure c (wrap1 n24) (UDP.nodeAddr dst) |
@@ -212,7 +215,7 @@ getUDPNodes' tcp seeking dst0 = do | |||
212 | , asymmData = pure (x,n8) | 215 | , asymmData = pure (x,n8) |
213 | } | 216 | } |
214 | , unwrapResponse = \case | 217 | , unwrapResponse = \case |
215 | OnionPacketResponse (OnionAnnounceResponse _ n24' r) | 218 | (_,OnionPacketResponse (OnionAnnounceResponse _ n24' r)) |
216 | -> decrypt (wrap0 n24') r >>= decodePlain | 219 | -> decrypt (wrap0 n24') r >>= decodePlain |
217 | x -> Left $ "getUDPNodes: unwrapResponse fail " ++ show x | 220 | x -> Left $ "getUDPNodes: unwrapResponse fail " ++ show x |
218 | } | 221 | } |
@@ -222,26 +225,28 @@ getUDPNodes' tcp seeking dst0 = do | |||
222 | return ( (ns,ns, const () <$> mb), gateway ) | 225 | return ( (ns,ns, const () <$> mb), gateway ) |
223 | 226 | ||
224 | 227 | ||
225 | handleOOB :: PublicKey -> ByteString -> NodeInfo -> NodeInfo -> IO (Maybe (RelayPacket -> RelayPacket)) | 228 | handleOOB :: PublicKey -> ByteString -> NodeInfo -> NodeInfo -> IO (Maybe (x -> x)) |
226 | handleOOB k bs src dst = do | 229 | handleOOB k bs src dst = do |
227 | dput XMisc $ "TODO: handleOOB " ++ show src | 230 | dput XMisc $ "TODO: handleOOB " ++ show src |
228 | return Nothing | 231 | return Nothing |
229 | 232 | ||
230 | handle2route :: OnionMessage Encrypted -> NodeInfo -> NodeInfo -> IO (Maybe (RelayPacket -> RelayPacket)) | 233 | handle2route :: OnionMessage Encrypted -> NodeInfo -> NodeInfo -> IO (Maybe (x -> x)) |
231 | handle2route o src dst = do | 234 | handle2route o src dst = do |
232 | dput XMisc $ "TODO: handle2route " ++ show src | 235 | dput XMisc $ "TODO: handle2route " ++ show src |
233 | return Nothing | 236 | return Nothing |
234 | 237 | ||
235 | tcpPing :: Client err () Nonce8 addr RelayPacket -> addr -> IO (Maybe ()) | 238 | tcpPing :: Show addr => Client err PacketNumber Nonce8 addr (Bool,RelayPacket) -> addr -> IO (Maybe ()) |
236 | tcpPing client dst = sendQuery client meth () dst | 239 | tcpPing client dst = do |
240 | dput XTCP $ "tcpPing " ++ show dst | ||
241 | sendQuery client meth () dst | ||
237 | where meth = MethodSerializer | 242 | where meth = MethodSerializer |
238 | { wrapQuery = \n8 src dst () -> RelayPing n8 | 243 | { wrapQuery = \n8 src dst () -> (True,RelayPing n8) |
239 | , unwrapResponse = \_ -> () | 244 | , unwrapResponse = \_ -> () |
240 | , methodTimeout = \n8 dst -> return (dst,5000000) | 245 | , methodTimeout = \n8 dst -> return (dst,5000000) |
241 | , method = () | 246 | , method = PingPacket |
242 | } | 247 | } |
243 | 248 | ||
244 | type RelayClient = Client String () Nonce8 NodeInfo RelayPacket | 249 | type RelayClient = Client String PacketNumber Nonce8 NodeInfo (Bool,RelayPacket) |
245 | 250 | ||
246 | -- | Create a new TCP relay client. Because polymorphic existential record | 251 | -- | Create a new TCP relay client. Because polymorphic existential record |
247 | -- updates are currently hard with GHC, this function accepts parameters for | 252 | -- updates are currently hard with GHC, this function accepts parameters for |
@@ -249,29 +254,34 @@ type RelayClient = Client String () Nonce8 NodeInfo RelayPacket | |||
249 | -- defaults are 'id' and 'tryPutMVar'. The resulting customized table state | 254 | -- defaults are 'id' and 'tryPutMVar'. The resulting customized table state |
250 | -- will be returned to the caller along with the new client. | 255 | -- will be returned to the caller along with the new client. |
251 | newClient :: TransportCrypto | 256 | newClient :: TransportCrypto |
252 | -> (MVar RelayPacket -> a) -- ^ store mvar for query | 257 | -> (MVar (Bool,RelayPacket) -> a) -- ^ store mvar for query |
253 | -> (a -> RelayPacket -> IO void) -- ^ load mvar for query | 258 | -> (a -> RelayPacket -> IO void) -- ^ load mvar for query |
254 | -> IO ( TVar (ChaChaDRG, Data.Word64Map.Word64Map a) | 259 | -> IO ( TVar (ChaChaDRG, Data.Word64Map.Word64Map a) |
255 | , Client String () Nonce8 NodeInfo RelayPacket) | 260 | , Client String PacketNumber Nonce8 NodeInfo (Bool,RelayPacket)) |
256 | newClient crypto store load = do | 261 | newClient crypto store load = do |
257 | net <- toxTCP crypto | 262 | net <- toxTCP crypto |
258 | drg <- drgNew | 263 | drg <- drgNew |
259 | map_var <- atomically $ newTVar (drg, Data.Word64Map.empty) | 264 | map_var <- atomically $ newTVar (drg, Data.Word64Map.empty) |
260 | return $ (,) map_var Client | 265 | return $ (,) map_var Client |
261 | { clientNet = net | 266 | { clientNet = {- XXX: Client type forces this pointless layering. -} layerTransport ((Right .) . (,) . (,) False) (,) net |
262 | , clientDispatcher = DispatchMethods | 267 | , clientDispatcher = DispatchMethods |
263 | { classifyInbound = \case | 268 | { classifyInbound = (. snd) $ \case |
264 | RelayPing n -> IsQuery () n | 269 | RelayPing n -> IsQuery PingPacket n |
265 | RelayPong n -> IsResponse n | 270 | RelayPong n -> IsResponse n |
266 | OnionPacketResponse (OnionAnnounceResponse n8 n24 ciphered) -> IsResponse n8 | 271 | OnionPacketResponse (OnionAnnounceResponse n8 n24 ciphered) -> IsResponse n8 |
267 | OnionPacketResponse o@(OnionToRouteResponse _) -> IsUnsolicited $ handle2route o | 272 | OnionPacketResponse o@(OnionToRouteResponse _) -> IsUnsolicited $ handle2route o |
268 | OOBRecv k bs -> IsUnsolicited $ handleOOB k bs | 273 | OOBRecv k bs -> IsUnsolicited $ handleOOB k bs |
269 | , lookupHandler = \() -> Just MethodHandler | 274 | , lookupHandler = \case |
270 | { methodParse = \(RelayPing n8) -> Right () | 275 | PingPacket -> Just MethodHandler |
271 | , methodSerialize = \n8 src dst () -> RelayPong n8 | 276 | { methodParse = \(_,RelayPing n8) -> Right () |
277 | , methodSerialize = \n8 src dst () -> (False, RelayPong n8) | ||
272 | , methodAction = \src () -> return () | 278 | , methodAction = \src () -> return () |
273 | } | 279 | } |
274 | , tableMethods = transactionMethods' store load (contramap (\(Nonce8 w64) -> w64) w64MapMethods) | 280 | w -> trace ("tcp-lookupHandler: "++show w) $ Just NoReply |
281 | { methodParse = \x -> Left "tcp-lookuphandler?" -- :: x -> Either err a | ||
282 | , noreplyAction = \addr a -> dput XTCP $ "tcp-lookupHandler: "++show w | ||
283 | } | ||
284 | , tableMethods = transactionMethods' store (\x -> load x . snd) (contramap (\(Nonce8 w64) -> w64) w64MapMethods) | ||
275 | $ first (either error Nonce8 . decode) . randomBytesGenerate 8 | 285 | $ first (either error Nonce8 . decode) . randomBytesGenerate 8 |
276 | } | 286 | } |
277 | , clientErrorReporter = logErrors { reportTimeout = reportTimeout ignoreErrors } | 287 | , clientErrorReporter = logErrors { reportTimeout = reportTimeout ignoreErrors } |