diff options
author | James Crayne <jim.crayne@gmail.com> | 2017-11-03 06:43:23 +0000 |
---|---|---|
committer | James Crayne <jim.crayne@gmail.com> | 2017-11-19 23:40:11 +0000 |
commit | ae2d321f380d4c3b3d967533693a1499f8d15a13 (patch) | |
tree | 87703b2f909c348d1e83decbbd41e7f1131c703c /src/Network/Tox/Crypto/Handlers.hs | |
parent | eeb4ec02d7d9135b788e0120ea48e5f55132c1df (diff) |
Refactor, and bitflags in binary message type
Diffstat (limited to 'src/Network/Tox/Crypto/Handlers.hs')
-rw-r--r-- | src/Network/Tox/Crypto/Handlers.hs | 97 |
1 files changed, 62 insertions, 35 deletions
diff --git a/src/Network/Tox/Crypto/Handlers.hs b/src/Network/Tox/Crypto/Handlers.hs index 0cb2d4db..d6f2de7e 100644 --- a/src/Network/Tox/Crypto/Handlers.hs +++ b/src/Network/Tox/Crypto/Handlers.hs | |||
@@ -13,6 +13,7 @@ import Control.Applicative | |||
13 | import Control.Monad | 13 | import Control.Monad |
14 | import Data.Time.Clock.POSIX | 14 | import Data.Time.Clock.POSIX |
15 | import qualified Data.ByteString as B | 15 | import qualified Data.ByteString as B |
16 | import Data.ByteString (ByteString) | ||
16 | import Control.Lens | 17 | import Control.Lens |
17 | import Data.Function | 18 | import Data.Function |
18 | import Data.Serialize as S | 19 | import Data.Serialize as S |
@@ -34,6 +35,21 @@ type IOHook addr x = addr -> x -> IO (Maybe (x -> x)) | |||
34 | type NetCryptoHook = IOHook NetCryptoSession CryptoData | 35 | type NetCryptoHook = IOHook NetCryptoSession CryptoData |
35 | type MsgTypeArray = A.UArray Word8 Word16 | 36 | type MsgTypeArray = A.UArray Word8 Word16 |
36 | 37 | ||
38 | |||
39 | -- | Information, that may be made visible in multiple sessions, as well | ||
40 | -- as displayed in some way to the user via mutiple views. | ||
41 | data SessionView = SessionView | ||
42 | { svNick :: TVar ByteString | ||
43 | , svStatus :: TVar UserStatus | ||
44 | , svStatusMsg :: TVar ByteString | ||
45 | , svGroups :: TVar (Map.Map GroupChatId (Set.Set SockAddr)) | ||
46 | , svCacheDir :: FilePath -- ^ directory path used if the session has to use the disk for cache | ||
47 | -- clean up only if space is needed | ||
48 | , svTmpDir :: FilePath -- Once off storage goes here, should clean up quickly | ||
49 | , svConfigDir :: FilePath -- profile related storage, etc, never clean up | ||
50 | } | ||
51 | |||
52 | |||
37 | data NetCryptoSession = NCrypto { ncState :: TVar NetCryptoSessionStatus | 53 | data NetCryptoSession = NCrypto { ncState :: TVar NetCryptoSessionStatus |
38 | , ncTheirBaseNonce :: TVar Nonce24 -- base nonce + packet number | 54 | , ncTheirBaseNonce :: TVar Nonce24 -- base nonce + packet number |
39 | , ncMyPacketNonce :: TVar Nonce24 -- base nonce + packet number | 55 | , ncMyPacketNonce :: TVar Nonce24 -- base nonce + packet number |
@@ -54,23 +70,29 @@ data NetCryptoSession = NCrypto { ncState :: TVar NetCryptoSessionStatus | |||
54 | , ncAllSessions :: NetCryptoSessions -- ^ may be needed if one net-crypto session | 70 | , ncAllSessions :: NetCryptoSessions -- ^ may be needed if one net-crypto session |
55 | -- needs to possibly start another, as is | 71 | -- needs to possibly start another, as is |
56 | -- the case in group chats | 72 | -- the case in group chats |
57 | , ncGroups :: TVar (Map.Map GroupChatId (Set.Set SockAddr)) | 73 | , ncView :: TVar SessionView |
58 | } | 74 | } |
59 | 75 | ||
60 | data NetCryptoSessions = NCSessions { netCryptoSessions :: TVar (Map.Map SockAddr NetCryptoSession) | 76 | data NetCryptoSessions = NCSessions { netCryptoSessions :: TVar (Map.Map SockAddr NetCryptoSession) |
61 | , transportCrypto :: TransportCrypto | 77 | , transportCrypto :: TransportCrypto |
62 | , defaultHooks :: Map.Map MessageType [NetCryptoHook] | 78 | , defaultHooks :: Map.Map MessageType [NetCryptoHook] |
63 | , defaultUnrecognizedHook :: MessageType -> NetCryptoHook | 79 | , defaultUnrecognizedHook :: MessageType -> NetCryptoHook |
80 | , sessionView :: SessionView | ||
64 | , msgTypeArray :: MsgTypeArray | 81 | , msgTypeArray :: MsgTypeArray |
65 | } | 82 | } |
66 | 83 | ||
67 | newSessionsState :: TransportCrypto -> (MessageType -> NetCryptoHook) -> Map.Map MessageType [NetCryptoHook] -> IO NetCryptoSessions | 84 | newSessionsState :: TransportCrypto -> (MessageType -> NetCryptoHook) -> Map.Map MessageType [NetCryptoHook] -> IO NetCryptoSessions |
68 | newSessionsState crypto unrechook hooks = do | 85 | newSessionsState crypto unrechook hooks = do |
69 | x <- atomically $ newTVar Map.empty | 86 | x <- atomically $ newTVar Map.empty |
87 | nick <- atomically $ newTVar B.empty | ||
88 | status <- atomically $ newTVar Online | ||
89 | statusmsg <- atomically $ newTVar B.empty | ||
90 | grps <- atomically $ newTVar Map.empty | ||
70 | return NCSessions { netCryptoSessions = x | 91 | return NCSessions { netCryptoSessions = x |
71 | , transportCrypto = crypto | 92 | , transportCrypto = crypto |
72 | , defaultHooks = hooks | 93 | , defaultHooks = hooks |
73 | , defaultUnrecognizedHook = unrechook | 94 | , defaultUnrecognizedHook = unrechook |
95 | , sessionView = SessionView { svNick = nick, svStatus = status, svStatusMsg = statusmsg, svGroups = grps } | ||
74 | , msgTypeArray = allMsgTypes -- todo make this a parameter | 96 | , msgTypeArray = allMsgTypes -- todo make this a parameter |
75 | } | 97 | } |
76 | 98 | ||
@@ -117,8 +139,8 @@ freshCryptoSession sessions | |||
117 | newsession <- generateSecretKey | 139 | newsession <- generateSecretKey |
118 | ncHooks0 <- atomically $ newTVar (defaultHooks sessions) | 140 | ncHooks0 <- atomically $ newTVar (defaultHooks sessions) |
119 | ncUnrecognizedHook0 <- atomically $ newTVar (defaultUnrecognizedHook sessions) | 141 | ncUnrecognizedHook0 <- atomically $ newTVar (defaultUnrecognizedHook sessions) |
120 | ncGroups0 <- atomically $ newTVar (Map.empty) | ||
121 | ncMessageTypes0 <- atomically $ newTVar (msgTypeArray sessions) | 142 | ncMessageTypes0 <- atomically $ newTVar (msgTypeArray sessions) |
143 | ncView0 <- atomically $ newTVar (sessionView sessions) | ||
122 | let netCryptoSession = | 144 | let netCryptoSession = |
123 | NCrypto { ncState = ncState0 | 145 | NCrypto { ncState = ncState0 |
124 | , ncTheirBaseNonce= ncTheirBaseNonce0 | 146 | , ncTheirBaseNonce= ncTheirBaseNonce0 |
@@ -132,8 +154,8 @@ freshCryptoSession sessions | |||
132 | , ncHooks = ncHooks0 | 154 | , ncHooks = ncHooks0 |
133 | , ncUnrecognizedHook = ncUnrecognizedHook0 | 155 | , ncUnrecognizedHook = ncUnrecognizedHook0 |
134 | , ncAllSessions = sessions | 156 | , ncAllSessions = sessions |
135 | , ncGroups = ncGroups0 | ||
136 | , ncMessageTypes = ncMessageTypes0 | 157 | , ncMessageTypes = ncMessageTypes0 |
158 | , ncView = ncView0 | ||
137 | } | 159 | } |
138 | atomically $ modifyTVar allsessions (Map.insert addr netCryptoSession) | 160 | atomically $ modifyTVar allsessions (Map.insert addr netCryptoSession) |
139 | 161 | ||
@@ -247,38 +269,7 @@ cryptoNetHandler sessions addr (NetCrypto (CryptoPacket nonce16 encrypted)) = do | |||
247 | writeTVar ncTheirBaseNonce y | 269 | writeTVar ncTheirBaseNonce y |
248 | -- then set session confirmed, | 270 | -- then set session confirmed, |
249 | atomically $ writeTVar ncState Confirmed | 271 | atomically $ writeTVar ncState Confirmed |
250 | hookmap <- atomically $ readTVar ncHooks | 272 | runCryptoHook session cd |
251 | -- run hook | ||
252 | flip fix (cd,hookmap) $ \lookupAgain (cd,hookmap) -> do | ||
253 | msgTyps <- atomically $ readTVar ncMessageTypes | ||
254 | let msgTyp = cd ^. messageType | ||
255 | msgTypMapped16 = msgTypes ! msgId cd | ||
256 | msgTypMapped = fromIntegral msgTypMapped16 | ||
257 | if msgTypMapped16 == 0 | ||
258 | then return id | ||
259 | else | ||
260 | case Map.lookup msgTypMapped hookmap of | ||
261 | Nothing -> do -- no recognizing hook, run ncUnrecognizedHook0, loopAgain on result | ||
262 | unrecognize <- atomically $ readTVar (ncUnrecognizedHook session) | ||
263 | mbConsume <- unrecognize msgTypMapped session cd | ||
264 | case mbConsume of | ||
265 | Just f -> do | ||
266 | -- ncUnrecognizedHook0 may have updated the hookmap | ||
267 | hookmap' <- atomically $ readTVar ncHooks | ||
268 | lookupAgain (f cd,hookmap') | ||
269 | Nothing -> return Nothing | ||
270 | Just hooks -> flip fix (hooks,cd,msgTypMapped) $ \loop (hooks,cd,typ) -> do | ||
271 | let _ = cd :: CryptoData | ||
272 | case (hooks,cd) of | ||
273 | ([],_) -> return Nothing | ||
274 | (hook:more,cd) -> do | ||
275 | r <- hook session cd :: IO (Maybe (CryptoData -> CryptoData)) | ||
276 | case r of | ||
277 | Just f -> let newcd = f cd | ||
278 | newtyp = newcd ^. messageType | ||
279 | in if newtyp == typ then loop (more,newcd,newtyp) | ||
280 | else lookupAgain (newcd,hookmap) | ||
281 | Nothing -> return Nothing -- message consumed | ||
282 | where | 273 | where |
283 | last2Bytes :: Nonce24 -> Word | 274 | last2Bytes :: Nonce24 -> Word |
284 | last2Bytes (Nonce24 bs) = case S.decode (B.drop 22 bs) of | 275 | last2Bytes (Nonce24 bs) = case S.decode (B.drop 22 bs) of |
@@ -286,6 +277,42 @@ cryptoNetHandler sessions addr (NetCrypto (CryptoPacket nonce16 encrypted)) = do | |||
286 | _ -> error "unreachable-last2Bytes" | 277 | _ -> error "unreachable-last2Bytes" |
287 | dATA_NUM_THRESHOLD = 21845 -- = 65535 / 3 | 278 | dATA_NUM_THRESHOLD = 21845 -- = 65535 / 3 |
288 | 279 | ||
280 | runCryptoHook :: NetCryptoSession -> CryptoData -> IO (Maybe (x -> x)) | ||
281 | runCryptoHook session@(NCrypto {ncState, ncHooks,ncSessionSecret,ncTheirSessionPublic,ncTheirBaseNonce,ncMessageTypes}) | ||
282 | cd@(CryptoData {bufferStart, bufferEnd, bufferData=cm}) = do | ||
283 | hookmap <- atomically $ readTVar ncHooks | ||
284 | -- run hook | ||
285 | flip fix (cd,hookmap) $ \lookupAgain (cd,hookmap) -> do | ||
286 | msgTypes <- atomically $ readTVar ncMessageTypes | ||
287 | let msgTyp = cd ^. messageType | ||
288 | msgTypMapped16 = msgTypes A.! fromEnum8 (msgID cm) | ||
289 | msgTypMapped = fromWord16 $ msgTypMapped16 | ||
290 | if msgTypMapped16 == 0 | ||
291 | then return $ Just id | ||
292 | else | ||
293 | case Map.lookup msgTypMapped hookmap of | ||
294 | Nothing -> do -- no recognizing hook, run ncUnrecognizedHook0, loopAgain on result | ||
295 | unrecognize <- atomically $ readTVar (ncUnrecognizedHook session) | ||
296 | mbConsume <- unrecognize msgTypMapped session cd | ||
297 | case mbConsume of | ||
298 | Just f -> do | ||
299 | -- ncUnrecognizedHook0 may have updated the hookmap | ||
300 | hookmap' <- atomically $ readTVar ncHooks | ||
301 | lookupAgain (f cd,hookmap') | ||
302 | Nothing -> return Nothing | ||
303 | Just hooks -> flip fix (hooks,cd,msgTypMapped) $ \loop (hooks,cd,typ) -> do | ||
304 | let _ = cd :: CryptoData | ||
305 | case (hooks,cd) of | ||
306 | ([],_) -> return Nothing | ||
307 | (hook:more,cd) -> do | ||
308 | r <- hook session cd :: IO (Maybe (CryptoData -> CryptoData)) | ||
309 | case r of | ||
310 | Just f -> let newcd = f cd | ||
311 | newtyp = newcd ^. messageType | ||
312 | in if newtyp == typ then loop (more,newcd,newtyp) | ||
313 | else lookupAgain (newcd,hookmap) | ||
314 | Nothing -> return Nothing -- message consumed | ||
315 | |||
289 | -- | construct a 'MsgTypeArray' for specified types, using their known common positions | 316 | -- | construct a 'MsgTypeArray' for specified types, using their known common positions |
290 | -- in the MessageId space if they have such a thing. | 317 | -- in the MessageId space if they have such a thing. |
291 | mkMsgTypes :: [MessageType] -> MsgTypeArray | 318 | mkMsgTypes :: [MessageType] -> MsgTypeArray |