summaryrefslogtreecommitdiff
path: root/examples/toxrelay.hs
blob: fdf0c011cfc17ba8060c0338dd8e7c1c967a38c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
{-# LANGUAGE ScopedTypeVariables #-}

import Control.Exception
import Control.Monad
import Control.Concurrent.STM
import qualified Data.ByteString as B
import Data.Function
import qualified Data.IntMap as IntMap
         ;import Data.IntMap (IntMap)
import Data.Serialize
import System.IO
import Data.Functor.Identity

import Crypto.Tox
import Data.Tox.Relay
import Network.StreamServer
import Network.Address (getBindAddress)
import Network.Tox (newCrypto)



hGetPrefixed :: Serialize a => Handle -> IO (Either String a)
hGetPrefixed h = do
    mlen <- runGet getWord16be <$> B.hGet h 2
    fmap join $ forM mlen $ \len -> runGet get <$> B.hGet h (fromIntegral len)

hGetSized :: forall x. (Sized x, Serialize x) => Handle -> IO (Either String x)
hGetSized h = runGet get <$> B.hGet h len
 where
    ConstSize len = size :: Size x

relaySession :: TransportCrypto -> TVar (IntMap Handle) -> (RelayPacket -> IO ()) -> sock -> Int -> Handle -> IO ()
relaySession crypto cons dispatch _ conid h = do
    atomically $ modifyTVar' cons $ IntMap.insert conid h
    -- mhello <- fmap (>>= \h -> decryptPayload (computeSharedSecret me (helloFrom h) (helloNonce h)) h) $ hGetSized h

    (hGetSized h >>=) $ mapM_ $ \helloE -> do

    let me = transportSecret crypto
        them = helloFrom helloE

    noncef <- lookupNonceFunction crypto me them
    let mhello = decryptPayload (noncef $ helloNonce helloE) helloE

    forM_ mhello $ \hello -> do

        (me',welcome) <- atomically $ do
            skey <- transportNewKey crypto
            dta <- HelloData (toPublic skey) <$> transportNewNonce crypto
            w24 <- transportNewNonce crypto
            return (skey, Welcome w24 $ pure dta)
        B.hPut h $ encode $ encryptPayload (noncef $ welcomeNonce welcome) welcome

        let them' = sessionPublicKey (runIdentity $ helloData hello)
        noncef' <- lookupNonceFunction crypto me' them'

        let _ = hello :: Hello Identity
        flip fix (sessionBaseNonce $ runIdentity $ helloData hello) $ \loop n24 -> do
            m <- (>>= decrypt (noncef' n24) >=> decodePlain) <$> hGetPrefixed h
            forM_ m $ \p -> do
                dispatch p
                loop (incrementNonce24 n24)
     `finally`
        atomically (modifyTVar' cons $ IntMap.delete conid)



main :: IO ()
main = do
    crypto <- newCrypto
    cons <- newTVarIO IntMap.empty
    a <- getBindAddress "33445" True
    h <- streamServer ServerConfig
                        { serverWarn = hPutStrLn stderr
                        , serverSession = relaySession crypto cons print
                        }
                      a

    putStrLn $ "ENTER to quit..."
    s <- getLine

    quitListening h