summaryrefslogtreecommitdiff
path: root/src/Network/Tox
diff options
context:
space:
mode:
authorjim@bo <jim@bo>2018-06-24 23:06:09 -0400
committerjoe <joe@jerkface.net>2018-06-25 17:06:18 -0400
commitf07d159805459c0c8c7b9fd546cdcfdfda750e41 (patch)
tree9c220fc1d8c2dd506a2ee8625b128703261218e2 /src/Network/Tox
parentd1e0191f6ea329ba2ffbc1b99fd41b5aec68765b (diff)
Feature Negotiation messages, serialization code
Diffstat (limited to 'src/Network/Tox')
-rw-r--r--src/Network/Tox/Crypto/Transport.hs103
1 files changed, 103 insertions, 0 deletions
diff --git a/src/Network/Tox/Crypto/Transport.hs b/src/Network/Tox/Crypto/Transport.hs
index c7fbfdc6..a5634d71 100644
--- a/src/Network/Tox/Crypto/Transport.hs
+++ b/src/Network/Tox/Crypto/Transport.hs
@@ -58,6 +58,8 @@ module Network.Tox.Crypto.Transport
58 , fromEnum16 58 , fromEnum16
59 , toEnum8 59 , toEnum8
60 , msgSizeParam 60 , msgSizeParam
61 , NegotiationID(..)
62 , NegotiationMsg(..)
61 ) where 63 ) where
62 64
63import Crypto.Tox 65import Crypto.Tox
@@ -74,12 +76,14 @@ import Data.Word
74import Data.Bits 76import Data.Bits
75import Crypto.Hash 77import Crypto.Hash
76import Control.Lens 78import Control.Lens
79import Control.Monad
77import Data.Text as T 80import Data.Text as T
78import Data.Text.Encoding as T 81import Data.Text.Encoding as T
79import Data.Serialize as S 82import Data.Serialize as S
80import Control.Arrow 83import Control.Arrow
81import DPut 84import DPut
82import Data.PacketQueue (toPNums) 85import Data.PacketQueue (toPNums)
86import Data.Function
83 87
84showCryptoMsg :: Word32 -> CryptoMessage -> [Char] 88showCryptoMsg :: Word32 -> CryptoMessage -> [Char]
85showCryptoMsg seqno (UpToN PacketRequest bytes) = "UpToN PacketRequest --> " ++ show (toPNums seqno $ B.unpack bytes) 89showCryptoMsg seqno (UpToN PacketRequest bytes) = "UpToN PacketRequest --> " ++ show (toPNums seqno $ B.unpack bytes)
@@ -1323,3 +1327,102 @@ data MessageName = Ping -- 0x00
1323-- (SockAddr -> NodeId) 1327-- (SockAddr -> NodeId)
1324 1328
1325 1329
1330-----------------------------------------------------------
1331-- Session feature negotiation, piggy back on AlivePacket(PING)
1332--
1333-- UpToN { msgID = PING{-16-}
1334-- , msgBytes = S.encode (UpToN { msgID = toEnum8 (fromEnum8 NegotiationID)
1335-- , msgBytes = payload
1336-- })
1337--
1338--
1339-- RefInfo = { Word32 -- this messsage (refnum), start with 1
1340-- , Word32 -- 0 if not replying, otherwise refnum of message it is in reply too
1341-- }
1342--
1343-- position = { Word8 -- 0 = top (MessageID) level, 1 = MessageName level
1344-- , Word8 -- MessageID
1345-- }
1346-- all MessageName-level messages use MESSAGE_GROUPCHAT as their primary Id
1347data NegotiationID -- payload --
1348 = DefineTopLevel -- Word8(NegotiationID)Word64(RefInfo):Word64(msg-type),Word16-position,Word64-type,Word24-position ...
1349 -- ^ Inform remote of your top-level map
1350 | DefineMap -- Word8(NegotiationID)Word64(RefInfo):Word32(map-num),Word16-position,Word64-type,Word24-position,Word64(msg-type), ...
1351 -- ^ Inform remote of available user-selectable second-level map
1352 | AnnounceSelectedMap -- Word8(NegotiationID)Word64(RefInfo):Word32(map-num)
1353 -- ^ Inform remote which second-level map he currently has selected
1354 | RequestMap -- Word8(NegotiationID)Word64(RefInfo):Word16-position,Word64-type,Word16-position,Word64(msg-type) ...
1355 -- ^ Ask remote for a selectable map supporting the message types at specific locations
1356 | SelectMap -- Word8(NegotiationID)Word64(RefInfo):Word32(map-num)
1357 -- ^ Tell remote which secondary map to use while interpretting your messages
1358 | DiscardMap -- Word8(NegotiationID)Word64(RefInfo):Word32(map-num)
1359 -- ^ Tell remote you aren't going to use the specified secondary map
1360 | DenyRequest -- Word8(NegotiationID)Word64(RefInfo)
1361 -- ^ Inform remote that you opted not to comply with his request (or selection), or there was some error
1362 deriving (Show,Eq,Ord,Enum,Bounded)
1363
1364instance Serialize NegotiationID where
1365 get = toEnum . fromIntegral <$> getWord8
1366 put x = putWord8 (fromIntegral . fromEnum $ x)
1367
1368data NegotiationMsg
1369 = NegMsg { negID :: NegotiationID
1370 , negNum :: Word32
1371 , negRef :: Word32
1372 , negMapNum :: Maybe Word32
1373 , negRange :: [((Word8,Word8),Word64)]
1374 } deriving (Eq,Show)
1375
1376instance Sized NegotiationMsg where
1377 size = VarSize $ \case
1378 x | negID x == DenyRequest -> 9
1379 x | negID x `Prelude.elem` [SelectMap,DiscardMap,AnnounceSelectedMap]
1380 -> 10
1381 x | negID x `Prelude.elem` [DefineTopLevel,RequestMap]
1382 , xs <- negRange x -> 9 + 10 * (Prelude.length xs)
1383
1384 x | negID x == DefineMap
1385 , xs <- negRange x -> 13 + 10 * (Prelude.length xs)
1386
1387instance Serialize NegotiationMsg where
1388 get = do
1389 i <- get :: Get NegotiationID
1390 num <- getWord32le :: Get Word32
1391 ref <- getWord32le :: Get Word32
1392 let getRangeReversed = flip fix [] $ \loop xs -> do
1393 emp <- isEmpty
1394 if emp then return xs
1395 else do
1396 level <- get :: Get Word8
1397 id <- get :: Get Word8
1398 typ <- getWord64le :: Get Word64
1399 loop (((level,id),typ):xs)
1400 let getRange = Prelude.reverse <$> getRangeReversed
1401 (mapNum,range)
1402 <- case i of
1403 x | x `Prelude.elem` [SelectMap,DiscardMap,AnnounceSelectedMap]
1404 -> do
1405 mapNum <- getWord32le :: Get Word32
1406 return (Just mapNum,[])
1407 x | x `Prelude.elem` [DefineTopLevel,RequestMap]
1408 -> do
1409 xs <- getRange
1410 return (Nothing,xs)
1411 DefineMap -> do
1412 mapNum <- getWord32le :: Get Word32
1413 xs <- getRange
1414 return (Just mapNum,xs)
1415
1416 _ -> return (Nothing,[])
1417 return $ NegMsg i num ref mapNum range
1418
1419 put msg = do
1420 putWord8 (fromIntegral . fromEnum $ negID msg)
1421 putWord32le (negNum msg)
1422 putWord32le (negRef msg)
1423 maybe (return ()) putWord32le (negMapNum msg)
1424 forM_ (negRange msg) $ \((lvl,id),typ) -> do
1425 putWord8 lvl
1426 putWord8 id
1427 putWord64le typ
1428