summaryrefslogtreecommitdiff
path: root/src/Data/Tox/Relay.hs
diff options
context:
space:
mode:
authorJames Crayne <jim.crayne@gmail.com>2019-09-28 13:43:29 -0400
committerJoe Crayne <joe@jerkface.net>2020-01-01 19:27:53 -0500
commit11987749fc6e6d3e53ea737d46d5ab13a16faeb8 (patch)
tree5716463275c2d3e902889db619908ded2a73971c /src/Data/Tox/Relay.hs
parentadd2c76bced51fde5e9917e7449ef52be70faf87 (diff)
Factor out some new libraries
word64-map: Data.Word64Map network-addr: Network.Address tox-crypto: Crypto.Tox lifted-concurrent: Control.Concurrent.Lifted.Instrument Control.Concurrent.Async.Lifted.Instrument psq-wrap: Data.Wrapper.PSQInt Data.Wrapper.PSQ minmax-psq: Data.MinMaxPSQ tasks: Control.Concurrent.Tasks kad: Network.Kademlia Network.Kademlia.Bootstrap Network.Kademlia.Routing Network.Kademlia.CommonAPI Network.Kademlia.Persistence Network.Kademlia.Search
Diffstat (limited to 'src/Data/Tox/Relay.hs')
-rw-r--r--src/Data/Tox/Relay.hs232
1 files changed, 0 insertions, 232 deletions
diff --git a/src/Data/Tox/Relay.hs b/src/Data/Tox/Relay.hs
deleted file mode 100644
index c563db8d..00000000
--- a/src/Data/Tox/Relay.hs
+++ /dev/null
@@ -1,232 +0,0 @@
1{-# LANGUAGE ConstraintKinds #-}
2{-# LANGUAGE DeriveDataTypeable #-}
3{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5{-# LANGUAGE KindSignatures #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE PatternSynonyms #-}
8{-# LANGUAGE StandaloneDeriving #-}
9{-# LANGUAGE UndecidableInstances #-}
10module Data.Tox.Relay where
11
12import Data.Aeson (ToJSON(..),FromJSON(..))
13import qualified Data.Aeson as JSON
14import Data.ByteString as B
15import Data.Data
16import Data.Functor.Contravariant
17import Data.Hashable
18import qualified Data.HashMap.Strict as HashMap
19import Data.Monoid
20import Data.Serialize
21import qualified Data.Vector as Vector
22import Data.Word
23import Network.Socket
24import qualified Rank2
25import qualified Text.ParserCombinators.ReadP as RP
26
27import Crypto.Tox
28import Data.Tox.Onion
29import qualified Network.Tox.NodeId as UDP
30
31newtype ConId = ConId Word8
32 deriving (Eq,Show,Ord,Data,Serialize)
33
34badcon :: ConId
35badcon = ConId 0
36
37-- Maps to a range -120 .. 119
38c2key :: ConId -> Maybe Int
39c2key (ConId x) | x < 16 = Nothing
40 | otherwise = Just $ case divMod (x - 15) 2 of
41 (q,0) -> negate $ fromIntegral q
42 (q,1) -> fromIntegral q
43
44-- Maps to range 16 .. 255
45-- negatives become odds
46key2c :: Int -> ConId
47key2c y = ConId $ if y < 0 then 15 + fromIntegral (negate y * 2)
48 else 16 + fromIntegral (y * 2)
49
50data RelayPacket
51 = RoutingRequest PublicKey
52 | RoutingResponse ConId PublicKey -- 0 for refusal, 16-255 for success.
53 | ConnectNotification ConId
54 | DisconnectNotification ConId
55 | RelayPing Nonce8
56 | RelayPong Nonce8
57 | OOBSend PublicKey ByteString
58 | OOBRecv PublicKey ByteString
59 | OnionPacket Nonce24 (Addressed (Forwarding N2 (OnionMessage Encrypted))) -- (OnionRequest N0)
60 | OnionPacketResponse (OnionMessage Encrypted)
61 -- 0x0A through 0x0F reserved for future use.
62 | RelayData ByteString ConId
63 deriving (Eq,Ord,Show,Data)
64
65newtype PacketNumber = PacketNumber { packetNumberToWord8 :: Word8 }
66 deriving (Eq,Ord,Show)
67
68pattern PingPacket = PacketNumber 4
69pattern OnionPacketID = PacketNumber 8
70
71packetNumber :: RelayPacket -> PacketNumber
72packetNumber (RelayData _ (ConId conid)) = PacketNumber $ conid -- 0 to 15 not allowed.
73packetNumber rp = PacketNumber $ fromIntegral $ pred $ constrIndex $ toConstr rp
74
75instance Sized RelayPacket where
76 size = mappend (ConstSize 1) $ VarSize $ \x -> case x of
77 RoutingRequest k -> 32
78 RoutingResponse rpid k -> 33
79 ConnectNotification conid -> 1
80 DisconnectNotification conid -> 1
81 RelayPing pingid -> 8
82 RelayPong pingid -> 8
83 OOBSend k bs -> 32 + B.length bs
84 OOBRecv k bs -> 32 + B.length bs
85 OnionPacket n24 query -> 24 + case contramap (`asTypeOf` query) size of
86 ConstSize n -> n
87 VarSize f -> f query
88 OnionPacketResponse answer -> case contramap (`asTypeOf` answer) size of
89 ConstSize n -> n
90 VarSize f -> f answer
91 RelayData bs _ -> B.length bs
92
93instance Serialize RelayPacket where
94
95 get = do
96 pktid <- getWord8
97 case pktid of
98 0 -> RoutingRequest <$> getPublicKey
99 1 -> RoutingResponse <$> get <*> getPublicKey
100 2 -> ConnectNotification <$> get
101 3 -> DisconnectNotification <$> get
102 4 -> RelayPing <$> get
103 5 -> RelayPong <$> get
104 6 -> OOBSend <$> getPublicKey <*> (remaining >>= getBytes)
105 7 -> OOBRecv <$> getPublicKey <*> (remaining >>= getBytes)
106 8 -> OnionPacket <$> get <*> get
107 9 -> OnionPacketResponse <$> get
108 conid -> (`RelayData` ConId conid) <$> (remaining >>= getBytes)
109
110 put rp = do
111 putWord8 $ packetNumberToWord8 $ packetNumber rp
112 case rp of
113 RoutingRequest k -> putPublicKey k
114 RoutingResponse rpid k -> put rpid >> putPublicKey k
115 ConnectNotification conid -> put conid
116 DisconnectNotification conid -> put conid
117 RelayPing pingid -> put pingid
118 RelayPong pingid -> put pingid
119 OOBSend k bs -> putPublicKey k >> putByteString bs
120 OOBRecv k bs -> putPublicKey k >> putByteString bs
121 OnionPacket n24 query -> put n24 >> put query
122 OnionPacketResponse answer -> put answer
123 RelayData bs _ -> putByteString bs
124
125-- | Initial client-to-server handshake message.
126newtype Hello (f :: * -> *) = Hello (Asymm (f HelloData))
127
128deriving instance Show (f HelloData) => Show (Hello f)
129
130helloFrom :: Hello f -> PublicKey
131helloFrom (Hello x) = senderKey x
132
133helloNonce :: Hello f -> Nonce24
134helloNonce (Hello x) = asymmNonce x
135
136helloData :: Hello f -> f HelloData
137helloData (Hello x) = asymmData x
138
139instance Rank2.Functor Hello where
140 f <$> Hello (Asymm k n dta) = Hello $ Asymm k n (f dta)
141
142instance Payload Serialize Hello where
143 mapPayload _ f (Hello (Asymm k n dta)) = Hello $ Asymm k n (f dta)
144
145instance Rank2.Foldable Hello where
146 foldMap f (Hello (Asymm k n dta)) = f dta
147
148instance Rank2.Traversable Hello where
149 traverse f (Hello (Asymm k n dta)) = Hello . Asymm k n <$> f dta
150
151instance Sized (Hello Encrypted) where
152 size = ConstSize 56 <> contramap helloData size
153
154instance Serialize (Hello Encrypted) where
155 get = Hello <$> getAsymm
156 put (Hello asym) = putAsymm asym
157
158data HelloData = HelloData
159 { sessionPublicKey :: PublicKey
160 , sessionBaseNonce :: Nonce24
161 }
162 deriving Show
163
164instance Sized HelloData where size = ConstSize 56
165
166instance Serialize HelloData where
167 get = HelloData <$> getPublicKey <*> get
168 put (HelloData k n) = putPublicKey k >> put n
169
170-- | Handshake server-to-client response packet.
171data Welcome (f :: * -> *) = Welcome
172 { welcomeNonce :: Nonce24
173 , welcomeData :: f HelloData
174 }
175
176deriving instance Show (f HelloData) => Show (Welcome f)
177
178instance Rank2.Functor Welcome where
179 f <$> Welcome n dta = Welcome n (f dta)
180
181instance Payload Serialize Welcome where
182 mapPayload _ f (Welcome n dta) = Welcome n (f dta)
183
184instance Rank2.Foldable Welcome where
185 foldMap f (Welcome _ dta) = f dta
186
187instance Rank2.Traversable Welcome where
188 traverse f (Welcome n dta) = Welcome n <$> f dta
189
190instance Sized (Welcome Encrypted) where
191 size = ConstSize 24 <> contramap welcomeData size
192
193instance Serialize (Welcome Encrypted) where
194 get = Welcome <$> get <*> get
195 put (Welcome n dta) = put n >> put dta
196
197data NodeInfo = NodeInfo
198 { udpNodeInfo :: UDP.NodeInfo
199 , tcpPort :: PortNumber
200 }
201 deriving (Eq,Ord)
202
203instance Read NodeInfo where
204 readsPrec _ = RP.readP_to_S $ do
205 udp <- RP.readS_to_P reads
206 port <- RP.between (RP.char '{') (RP.char '}') $ do
207 mapM_ RP.char ("tcp:" :: String)
208 w16 <- RP.readS_to_P reads
209 return $ fromIntegral (w16 :: Word16)
210 return $ NodeInfo udp port
211
212instance ToJSON NodeInfo where
213 toJSON (NodeInfo udp port) = case (toJSON udp) of
214 JSON.Object tbl -> JSON.Object $ HashMap.insert "tcp_ports"
215 (JSON.Array $ Vector.fromList
216 [JSON.Number (fromIntegral port)])
217 tbl
218 x -> x -- Shouldn't happen.
219
220instance FromJSON NodeInfo where
221 parseJSON json = do
222 udp <- parseJSON json
223 port <- case json of
224 JSON.Object v -> do
225 portnum:_ <- v JSON..: "tcp_ports"
226 return (fromIntegral (portnum :: Word16))
227 _ -> fail "TCP.NodeInfo: Expected JSON object."
228 return $ NodeInfo udp port
229
230instance Hashable NodeInfo where
231 hashWithSalt s n = hashWithSalt s (udpNodeInfo n)
232