diff options
author | jim@bo <jim@bo> | 2018-06-24 23:06:09 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2018-06-25 17:06:18 -0400 |
commit | f07d159805459c0c8c7b9fd546cdcfdfda750e41 (patch) | |
tree | 9c220fc1d8c2dd506a2ee8625b128703261218e2 /src/Network/Tox | |
parent | d1e0191f6ea329ba2ffbc1b99fd41b5aec68765b (diff) |
Feature Negotiation messages, serialization code
Diffstat (limited to 'src/Network/Tox')
-rw-r--r-- | src/Network/Tox/Crypto/Transport.hs | 103 |
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 | ||
63 | import Crypto.Tox | 65 | import Crypto.Tox |
@@ -74,12 +76,14 @@ import Data.Word | |||
74 | import Data.Bits | 76 | import Data.Bits |
75 | import Crypto.Hash | 77 | import Crypto.Hash |
76 | import Control.Lens | 78 | import Control.Lens |
79 | import Control.Monad | ||
77 | import Data.Text as T | 80 | import Data.Text as T |
78 | import Data.Text.Encoding as T | 81 | import Data.Text.Encoding as T |
79 | import Data.Serialize as S | 82 | import Data.Serialize as S |
80 | import Control.Arrow | 83 | import Control.Arrow |
81 | import DPut | 84 | import DPut |
82 | import Data.PacketQueue (toPNums) | 85 | import Data.PacketQueue (toPNums) |
86 | import Data.Function | ||
83 | 87 | ||
84 | showCryptoMsg :: Word32 -> CryptoMessage -> [Char] | 88 | showCryptoMsg :: Word32 -> CryptoMessage -> [Char] |
85 | showCryptoMsg seqno (UpToN PacketRequest bytes) = "UpToN PacketRequest --> " ++ show (toPNums seqno $ B.unpack bytes) | 89 | showCryptoMsg 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 | ||
1347 | data 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 | |||
1364 | instance Serialize NegotiationID where | ||
1365 | get = toEnum . fromIntegral <$> getWord8 | ||
1366 | put x = putWord8 (fromIntegral . fromEnum $ x) | ||
1367 | |||
1368 | data 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 | |||
1376 | instance 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 | |||
1387 | instance 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 | |||