summaryrefslogtreecommitdiff
path: root/src/Network/DHT/Tox.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/DHT/Tox.hs')
-rw-r--r--src/Network/DHT/Tox.hs112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/Network/DHT/Tox.hs b/src/Network/DHT/Tox.hs
new file mode 100644
index 00000000..d6fc866f
--- /dev/null
+++ b/src/Network/DHT/Tox.hs
@@ -0,0 +1,112 @@
1{-# LANGUAGE TypeFamilies #-}
2{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
3module Network.DHT.Tox where
4
5import Data.Serialize
6import Data.Default
7import Text.PrettyPrint.HughesPJClass
8
9import Network.DHT.Types
10import Network.DatagramServer.Types
11import qualified Network.DatagramServer.Tox as Tox
12import Network.KRPC.Method
13import Data.Word
14import Data.ByteString (ByteString)
15import Data.IP
16import Data.Bool
17import Data.Maybe
18import Control.Monad
19import System.Random
20
21instance Kademlia Tox.Message where
22 data DHTData Tox.Message ip = ToxData
23 namePing _ = Tox.Ping
24 nameFindNodes _ = Tox.GetNodes
25 initializeDHTData = return ToxData
26
27instance Pretty (NodeId Tox.Message) where
28 pPrint (Tox.NodeId nid) = encodeHexDoc nid
29
30instance Serialize (Query Tox.Message (Ping Tox.Message)) where
31 get = getToxPing False Network.DHT.Types.Query Tox.QueryNonce
32 put (Network.DHT.Types.Query extra Ping) = putToxPing False (Tox.qryNonce extra)
33instance Serialize (Response Tox.Message (Ping Tox.Message)) where
34 get = getToxPing True Network.DHT.Types.Response Tox.ResponseNonce
35 put (Network.DHT.Types.Response extra Ping) = putToxPing True (Tox.rspNonce extra)
36
37instance Serialize (Query Tox.Message (FindNode Tox.Message ip)) where
38 get = do
39 nid <- get
40 n8 <- get
41 return $ Network.DHT.Types.Query (Tox.QueryNonce n8) (FindNode nid)
42 put (Network.DHT.Types.Query (Tox.QueryNonce n8) (FindNode nid)) = do
43 put nid
44 put n8
45instance Serialize (Response Tox.Message (NodeFound Tox.Message IPv4)) where
46 get = do
47 num <- get :: Get Word8
48 when (num > 4) $ fail "Too many nodes in Tox get-nodes reply"
49 ns0 <- sequence $ replicate (fromIntegral num) (nodeFormatToNodeInfo <$> get)
50 -- TODO: Allow tcp and ipv6. For now filtering to udp ip4...
51 let ns = flip mapMaybe ns0 $ \(NodeInfo nid addr u) -> do
52 guard $ not u
53 ip4 <- fromAddr addr
54 return $ NodeInfo nid ip4 ()
55 n8 <- get
56 return $ Network.DHT.Types.Response (Tox.ResponseNonce n8) $ NodeFound ns
57 put (Network.DHT.Types.Response (Tox.ResponseNonce n8) (NodeFound ns)) = do
58 put ( fromIntegral (length ns) :: Word8 )
59 forM_ ns $ \(NodeInfo nid ip4 ()) -> do
60 put Tox.NodeFormat { nodePublicKey = nid
61 , nodeIsTCP = False
62 , nodeIP = IPv4 (nodeHost ip4)
63 , nodePort = nodePort ip4
64 }
65 put n8
66
67instance KRPC Tox.Message (Query Tox.Message (FindNode Tox.Message IPv4))
68 (Response Tox.Message (NodeFound Tox.Message IPv4)) where
69 method = Method Tox.GetNodes
70 validateExchange = validateToxExchange
71 makeQueryExtra _ _ _ _ = Tox.QueryNonce <$> randomIO
72 makeResponseExtra _ _ q _ = return $ Tox.ResponseNonce $ Tox.qryNonce $ queryExtra q
73 messageSender q _ = Tox.msgClient q
74 messageResponder _ r = Tox.msgClient r
75
76instance KRPC Tox.Message (Query Tox.Message (Ping Tox.Message))
77 (Response Tox.Message (Ping Tox.Message)) where
78 method = Method Tox.Ping
79 validateExchange = validateToxExchange
80 makeQueryExtra _ _ _ _ = Tox.QueryNonce <$> randomIO
81 makeResponseExtra _ _ q _ = return $ Tox.ResponseNonce $ Tox.qryNonce $ queryExtra q
82 messageSender q _ = Tox.msgClient q
83 messageResponder _ r = Tox.msgClient r
84
85instance DataHandlers ByteString Tox.Message
86
87instance Default Bool where def = False
88
89getToxPing isPong c n = do
90 q'r <- get :: Get Word8
91 when (bool 0 1 isPong /= q'r) $
92 fail "Tox ping/pong parse fail."
93 n8 <- get :: Get Tox.Nonce8
94 return $ c (n n8) Ping
95
96putToxPing isPong n8 = do
97 put (bool 0 1 isPong :: Word8)
98 put n8
99
100validateToxExchange q r = qnonce == rnonce
101 where
102 qnonce = Tox.qryNonce . queryExtra . Tox.msgPayload $ q
103 rnonce = Tox.rspNonce . responseExtra . Tox.msgPayload $ r
104
105
106nodeFormatToNodeInfo nf = NodeInfo nid addr u
107 where
108 u = Tox.nodeIsTCP nf
109 addr = NodeAddr (Tox.nodeIP nf) (Tox.nodePort nf)
110 nid = Tox.nodePublicKey nf
111
112-- instance Default Bool where def = False