diff options
author | James Crayne <jim.crayne@gmail.com> | 2019-09-28 13:43:29 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2020-01-01 19:27:53 -0500 |
commit | 11987749fc6e6d3e53ea737d46d5ab13a16faeb8 (patch) | |
tree | 5716463275c2d3e902889db619908ded2a73971c /src/Data/Tox/Relay.hs | |
parent | add2c76bced51fde5e9917e7449ef52be70faf87 (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.hs | 232 |
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 #-} | ||
10 | module Data.Tox.Relay where | ||
11 | |||
12 | import Data.Aeson (ToJSON(..),FromJSON(..)) | ||
13 | import qualified Data.Aeson as JSON | ||
14 | import Data.ByteString as B | ||
15 | import Data.Data | ||
16 | import Data.Functor.Contravariant | ||
17 | import Data.Hashable | ||
18 | import qualified Data.HashMap.Strict as HashMap | ||
19 | import Data.Monoid | ||
20 | import Data.Serialize | ||
21 | import qualified Data.Vector as Vector | ||
22 | import Data.Word | ||
23 | import Network.Socket | ||
24 | import qualified Rank2 | ||
25 | import qualified Text.ParserCombinators.ReadP as RP | ||
26 | |||
27 | import Crypto.Tox | ||
28 | import Data.Tox.Onion | ||
29 | import qualified Network.Tox.NodeId as UDP | ||
30 | |||
31 | newtype ConId = ConId Word8 | ||
32 | deriving (Eq,Show,Ord,Data,Serialize) | ||
33 | |||
34 | badcon :: ConId | ||
35 | badcon = ConId 0 | ||
36 | |||
37 | -- Maps to a range -120 .. 119 | ||
38 | c2key :: ConId -> Maybe Int | ||
39 | c2key (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 | ||
46 | key2c :: Int -> ConId | ||
47 | key2c y = ConId $ if y < 0 then 15 + fromIntegral (negate y * 2) | ||
48 | else 16 + fromIntegral (y * 2) | ||
49 | |||
50 | data 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 | |||
65 | newtype PacketNumber = PacketNumber { packetNumberToWord8 :: Word8 } | ||
66 | deriving (Eq,Ord,Show) | ||
67 | |||
68 | pattern PingPacket = PacketNumber 4 | ||
69 | pattern OnionPacketID = PacketNumber 8 | ||
70 | |||
71 | packetNumber :: RelayPacket -> PacketNumber | ||
72 | packetNumber (RelayData _ (ConId conid)) = PacketNumber $ conid -- 0 to 15 not allowed. | ||
73 | packetNumber rp = PacketNumber $ fromIntegral $ pred $ constrIndex $ toConstr rp | ||
74 | |||
75 | instance 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 | |||
93 | instance 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. | ||
126 | newtype Hello (f :: * -> *) = Hello (Asymm (f HelloData)) | ||
127 | |||
128 | deriving instance Show (f HelloData) => Show (Hello f) | ||
129 | |||
130 | helloFrom :: Hello f -> PublicKey | ||
131 | helloFrom (Hello x) = senderKey x | ||
132 | |||
133 | helloNonce :: Hello f -> Nonce24 | ||
134 | helloNonce (Hello x) = asymmNonce x | ||
135 | |||
136 | helloData :: Hello f -> f HelloData | ||
137 | helloData (Hello x) = asymmData x | ||
138 | |||
139 | instance Rank2.Functor Hello where | ||
140 | f <$> Hello (Asymm k n dta) = Hello $ Asymm k n (f dta) | ||
141 | |||
142 | instance Payload Serialize Hello where | ||
143 | mapPayload _ f (Hello (Asymm k n dta)) = Hello $ Asymm k n (f dta) | ||
144 | |||
145 | instance Rank2.Foldable Hello where | ||
146 | foldMap f (Hello (Asymm k n dta)) = f dta | ||
147 | |||
148 | instance Rank2.Traversable Hello where | ||
149 | traverse f (Hello (Asymm k n dta)) = Hello . Asymm k n <$> f dta | ||
150 | |||
151 | instance Sized (Hello Encrypted) where | ||
152 | size = ConstSize 56 <> contramap helloData size | ||
153 | |||
154 | instance Serialize (Hello Encrypted) where | ||
155 | get = Hello <$> getAsymm | ||
156 | put (Hello asym) = putAsymm asym | ||
157 | |||
158 | data HelloData = HelloData | ||
159 | { sessionPublicKey :: PublicKey | ||
160 | , sessionBaseNonce :: Nonce24 | ||
161 | } | ||
162 | deriving Show | ||
163 | |||
164 | instance Sized HelloData where size = ConstSize 56 | ||
165 | |||
166 | instance 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. | ||
171 | data Welcome (f :: * -> *) = Welcome | ||
172 | { welcomeNonce :: Nonce24 | ||
173 | , welcomeData :: f HelloData | ||
174 | } | ||
175 | |||
176 | deriving instance Show (f HelloData) => Show (Welcome f) | ||
177 | |||
178 | instance Rank2.Functor Welcome where | ||
179 | f <$> Welcome n dta = Welcome n (f dta) | ||
180 | |||
181 | instance Payload Serialize Welcome where | ||
182 | mapPayload _ f (Welcome n dta) = Welcome n (f dta) | ||
183 | |||
184 | instance Rank2.Foldable Welcome where | ||
185 | foldMap f (Welcome _ dta) = f dta | ||
186 | |||
187 | instance Rank2.Traversable Welcome where | ||
188 | traverse f (Welcome n dta) = Welcome n <$> f dta | ||
189 | |||
190 | instance Sized (Welcome Encrypted) where | ||
191 | size = ConstSize 24 <> contramap welcomeData size | ||
192 | |||
193 | instance Serialize (Welcome Encrypted) where | ||
194 | get = Welcome <$> get <*> get | ||
195 | put (Welcome n dta) = put n >> put dta | ||
196 | |||
197 | data NodeInfo = NodeInfo | ||
198 | { udpNodeInfo :: UDP.NodeInfo | ||
199 | , tcpPort :: PortNumber | ||
200 | } | ||
201 | deriving (Eq,Ord) | ||
202 | |||
203 | instance 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 | |||
212 | instance 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 | |||
220 | instance 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 | |||
230 | instance Hashable NodeInfo where | ||
231 | hashWithSalt s n = hashWithSalt s (udpNodeInfo n) | ||
232 | |||