summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjim@bo <jim@bo>2018-06-23 02:51:56 -0400
committerjim@bo <jim@bo>2018-06-23 05:56:39 -0400
commit8f541d5e4f81ad7766986c48e4296e4d4ec5788b (patch)
treec41657c1326771b17c8cd4968f56e83e6d765c43
parent5c42256bb4bbd97b6d179e992eb762625a8dc2b4 (diff)
OutGoing hooks so SessionView is updated etc
-rw-r--r--dht-client.cabal6
-rw-r--r--examples/dhtd.hs114
-rw-r--r--src/Data/Word64RangeMap.hs6
-rw-r--r--src/Network/Tox/Crypto/Handlers.hs139
4 files changed, 211 insertions, 54 deletions
diff --git a/dht-client.cabal b/dht-client.cabal
index 7382eb76..aa2ab6cc 100644
--- a/dht-client.cabal
+++ b/dht-client.cabal
@@ -92,6 +92,7 @@ library
92 Data.CyclicBuffer 92 Data.CyclicBuffer
93 Data.Word64Map 93 Data.Word64Map
94 Data.Word64RangeMap 94 Data.Word64RangeMap
95 Data.Word64RangeMap.Unboxed
95 OnionRouter 96 OnionRouter
96 Network.Tox 97 Network.Tox
97 Network.Tox.Transport 98 Network.Tox.Transport
@@ -273,6 +274,7 @@ executable dhtd
273 default-language: Haskell2010 274 default-language: Haskell2010
274 build-depends: base, network, bytestring, hashable, deepseq 275 build-depends: base, network, bytestring, hashable, deepseq
275 , aeson 276 , aeson
277 , array
276 , pretty 278 , pretty
277 , dht-client 279 , dht-client
278 , unix 280 , unix
@@ -288,7 +290,11 @@ executable dhtd
288 , monad-control 290 , monad-control
289 , xml-types 291 , xml-types
290 , conduit 292 , conduit
293 , conduit-extra
291 , transformers 294 , transformers
295 , filepath
296 , process
297 , cereal-conduit >= 0.7.3
292 298
293 if flag(thread-debug) 299 if flag(thread-debug)
294 build-depends: time 300 build-depends: time
diff --git a/examples/dhtd.hs b/examples/dhtd.hs
index 1821cb1c..8e34d4fe 100644
--- a/examples/dhtd.hs
+++ b/examples/dhtd.hs
@@ -62,7 +62,9 @@ import qualified Data.HashMap.Strict as HashMap
62import qualified Data.Text as T 62import qualified Data.Text as T
63import qualified Data.Text.Encoding as T 63import qualified Data.Text.Encoding as T
64import System.Posix.Signals 64import System.Posix.Signals
65 65import qualified Data.Array
66import qualified Data.Array.Unboxed as U
67import qualified Data.Conduit as Conduit
66 68
67import Announcer 69import Announcer
68import Announcer.Tox 70import Announcer.Tox
@@ -103,6 +105,13 @@ import OnionRouter
103import PingMachine 105import PingMachine
104import Data.PacketQueue 106import Data.PacketQueue
105import qualified Data.Word64Map as W64 107import qualified Data.Word64Map as W64
108import System.FilePath
109import System.Process
110import System.Posix.IO
111import Data.Word64RangeMap
112import Network.Tox.Crypto.Transport
113import Data.Conduit.Cereal
114import qualified Data.Conduit.Binary as Conduit
106 115
107-- Presence imports. 116-- Presence imports.
108import ConsoleWriter 117import ConsoleWriter
@@ -932,7 +941,9 @@ clientSession s@Session{..} sock cnum h = do
932 941
933 -- necrypto <FRIEND-TOXID> 942 -- necrypto <FRIEND-TOXID>
934 -- establish a netcrypto session with specified person 943 -- establish a netcrypto session with specified person
935 ("netcrypto", s) -> cmd0 $ netcrypto (Map.lookup netname dhts) selectedKey h roster mbTox (strp s) 944 ("netcrypto", s) -> cmd0 $ do
945 let exes = Map.fromList [("atox",("/usr/bin/tmux -c","atox"))]
946 netcrypto (Map.lookup netname dhts) selectedKey h roster mbTox exes (strp s)
936 ("g", s) | Just DHT{..} <- Map.lookup netname dhts 947 ("g", s) | Just DHT{..} <- Map.lookup netname dhts
937 -> cmd0 $ do 948 -> cmd0 $ do
938 -- arguments: method 949 -- arguments: method
@@ -1282,11 +1293,12 @@ netcrypto
1282 -> ClientHandle 1293 -> ClientHandle
1283 -> ContactInfo extra1 1294 -> ContactInfo extra1
1284 -> Maybe (Tox.Tox extra2) 1295 -> Maybe (Tox.Tox extra2)
1296 -> Map.Map String (String,String) -- profile name to (multiplexer,exe name) for supported child executables
1285 -> String 1297 -> String
1286 -> IO () 1298 -> IO ()
1287netcrypto _ _ h _ Nothing _ = hPutClient h "Requires Tox enabled." 1299netcrypto _ _ h _ Nothing _ _ = hPutClient h "Requires Tox enabled."
1288netcrypto _ Nothing h _ _ _ = hPutClient h "No key is selected, see k command." 1300netcrypto _ Nothing h _ _ _ _ = hPutClient h "No key is selected, see k command."
1289netcrypto (Just (DHT {..})) (Just mypubkey) h roster (Just tox) keystr = 1301netcrypto (Just (DHT {..})) (Just mypubkey) h roster (Just tox) exes paramStr =
1290 either 1302 either
1291 (const $ 1303 (const $
1292 either 1304 either
@@ -1297,6 +1309,25 @@ netcrypto (Just (DHT {..})) (Just mypubkey) h roster (Just tox) keystr =
1297 (goPubkey . Tox.id2key) $ 1309 (goPubkey . Tox.id2key) $
1298 readEither keystr -- attempt read as NodeId type 1310 readEither keystr -- attempt read as NodeId type
1299 where 1311 where
1312 params = words paramStr
1313 keystr = bool (head params) "" (null params)
1314 -- TODO:
1315 -- execProfiles:
1316 -- atox@24-25,48-51,64-45 gnome-tox-notifier@24-25,49,50
1317 -- ^-- word64 type values that should be forwarded to this process
1318 execParams=drop 1 params
1319 parseExecParam :: String -> (String,[(Maybe Word64,Maybe Word64)])
1320 parseExecParam param = let (name,drop 1 -> rangesCombined) = span (/='@') param
1321 wordsBy x str = groupBy (const (/=x)) str
1322 rangesUnparsed = wordsBy ',' rangesCombined
1323 parseRange :: String -> (Maybe Word64,Maybe Word64)
1324 parseRange "all" = (Nothing,Nothing)
1325 parseRange x = let (low,drop 1 -> high) = break (==',') x
1326 in (readMaybe low,readMaybe high)
1327 in (name,map parseRange rangesUnparsed)
1328 execs = map parseExecParam execParams
1329
1330
1300 goNodeInfo userkey_nodeinfo = do 1331 goNodeInfo userkey_nodeinfo = do
1301 msec <- 1332 msec <-
1302 atomically $ do 1333 atomically $ do
@@ -1314,7 +1345,78 @@ netcrypto (Just (DHT {..})) (Just mypubkey) h roster (Just tox) keystr =
1314 Just account -> do 1345 Just account -> do
1315 now <- getPOSIXTime 1346 now <- getPOSIXTime
1316 atomically $ setContactAddr now their_pub their_addr account 1347 atomically $ setContactAddr now their_pub their_addr account
1317 Tox.netCrypto tox sec their_pub 1348 sessions <- Tox.netCrypto tox sec their_pub
1349 exeDir <- takeDirectory <$> getExecutablePath
1350 forM_ sessions $ \session -> do
1351 forM_ execs $ \(exekey,ranges) -> do
1352 case Map.lookup exekey exes of
1353 Nothing -> return ()
1354 Just (multiplexer,exename) -> do
1355 let exepath = exeDir </> exename
1356 (myReadFd,myWriteFd) <- System.Posix.IO.createPipe
1357 myRead <- fdToHandle myReadFd
1358 myWrite <- fdToHandle myWriteFd
1359 whoAmI <- atomically $ newTVar mypubkey
1360 whoAreThey <- atomically $ newTVar their_pub
1361 let fdArgs = [show myWriteFd,show myReadFd]
1362 if null multiplexer
1363 then callProcess exepath fdArgs
1364 else do
1365 let (multiplexer_exe,multiplexer_args) = splitAt 1 (words multiplexer)
1366 callProcess multiplexer (multiplexer_args ++ [intercalate " " (exepath:fdArgs)])
1367 -- tell subprocess who is talking to who
1368 B.hPutStr myWrite ("\NUL\NUL" `B.append` S.encode (Tox.key2id mypubkey))
1369 B.hPutStr myWrite ("\NUL\SOH" `B.append` S.encode (Tox.key2id their_pub))
1370 -- add hooks so subprocess is updated on incoming
1371 let makeHook session typ
1372 = \session msg
1373 -> do -- if (getMessageType msg == typ)
1374 me <- atomically $ readTVar whoAmI
1375 when (me /= mypubkey) $ do
1376 atomically $ writeTVar whoAmI mypubkey
1377 B.hPutStr myWrite ("\NUL\NUL" `B.append` S.encode (Tox.key2id mypubkey))
1378 them <- atomically $ readTVar whoAreThey
1379 when (them /= their_pub) $ do
1380 atomically $ writeTVar whoAreThey their_pub
1381 B.hPutStr myWrite ("\NUL\SOH" `B.append` S.encode (Tox.key2id their_pub))
1382 B.hPutStr myWrite (S.encode msg)
1383 return (Just id)
1384 addHooks currentHooks typs = forM_ typs $ \typ -> modifyTVar (Tox.ncHooks session) (Map.insert typ (currentHooks typ ++ [makeHook session typ]))
1385 case ranges of
1386 [(Nothing,Nothing)] -> atomically $ do
1387 typs <- map fromWord64 . filter (/=0) . U.elems <$> readTVar (Tox.ncIncomingTypeArray session)
1388 addHooks (const []) typs
1389 _ -> atomically . forM_ ranges $ \range -> do
1390 case range of
1391 (Just first,Just last) -> do
1392 let typs = map fromWord64 [first .. last]
1393 hooks <- readTVar (Tox.ncHooks session)
1394 let currentHooks typ = fromMaybe [] (Map.lookup typ hooks)
1395 addHooks currentHooks typs
1396 -- forward messages from subprocess
1397 forwardThread <- forkIO $ do
1398 tid <- myThreadId
1399 let sidStr = printf "(%x)" (Tox.ncSessionId session)
1400 labelThread tid (exekey ++ ".forward" ++ sidStr)
1401 let myconduit = Conduit.sourceHandle myRead .| conduitGet2 S.get -- :: ConduitT i CryptoMessage IO ()
1402 Conduit.runConduit (myconduit .| awaitForever (\msg -> do
1403 let typ = toWord64 (getMessageType msg)
1404 mbSendIt <- liftIO $ atomically (lookupInRangeMap typ (Tox.ncOutHooks session))
1405 case mbSendIt of
1406 Just sendit -> liftIO . void $ sendit (Tox.toxCryptoKeys tox) session msg
1407 Nothing -> return () -- do
1408 -- uncomment to let unhooked pass thru:
1409 -- if lossyness (msgId msg) == Lossless
1410 -- then sendLossless (Tox.toxCryptoKeys tox) session msg
1411 -- else sendLossy (Tox.toxCryptoKeys tox) session msg
1412 ))
1413 -- add hook to killThread on kill packet
1414 atomically $ do
1415 hooks <- readTVar (Tox.ncHooks session)
1416 let currentHooks = fromMaybe [] $ Map.lookup (Msg KillPacket) hooks
1417 let myhook :: Tox.NetCryptoSession -> CryptoMessage -> IO (Maybe (CryptoMessage -> CryptoMessage))
1418 myhook _ _ = killThread forwardThread >> return (Just id)
1419 modifyTVar' (Tox.ncHooks session) (Map.insert (Msg KillPacket) (currentHooks ++ [myhook]))
1318 hPutClient h "Handshake sent" 1420 hPutClient h "Handshake sent"
1319 goPubkey their_pub = do 1421 goPubkey their_pub = do
1320 msec <- 1422 msec <-
diff --git a/src/Data/Word64RangeMap.hs b/src/Data/Word64RangeMap.hs
index f4736d59..2e4cc8b7 100644
--- a/src/Data/Word64RangeMap.hs
+++ b/src/Data/Word64RangeMap.hs
@@ -20,14 +20,14 @@ import Data.IORef
20 20
21type OuterIndex = Int 21type OuterIndex = Int
22type Index = Word64 22type Index = Word64
23type InnerArray b = UArray Index b 23type InnerArray b = Array Index b
24 24
25-- | Although this type includes a parameter for index, the code assumes bounds start at 0 25-- | Although this type includes a parameter for index, the code assumes bounds start at 0
26-- and the index has 'Integral', and 'Num' instances. 26-- and the index has 'Integral', and 'Num' instances.
27newtype RefArray r ma i e = RefArray (r (ma i e)) 27newtype RefArray r ma i e = RefArray (r (ma i e))
28 28
29-- convenient contraint kind 29-- convenient contraint kind
30type RangeArray rangeArray m b ref = (IArray UArray b, MArray rangeArray (InnerArray b) m, Reference ref m) 30type RangeArray rangeArray m b ref = (MArray rangeArray (InnerArray b) m, Reference ref m)
31-- The RangeMap type, to be used with the above constraint 31-- The RangeMap type, to be used with the above constraint
32type RangeMap rangeArray b ref = RefArray ref rangeArray OuterIndex (InnerArray b) 32type RangeMap rangeArray b ref = RefArray ref rangeArray OuterIndex (InnerArray b)
33 33
@@ -64,7 +64,7 @@ instance (Reference r m, MArray ma e m) => MArray (RefArray r ma) e m where
64 unsafeWrite (RefArray r) i e = modifyRef r (\x -> Base.unsafeWrite x i e >> return (x,())) 64 unsafeWrite (RefArray r) i e = modifyRef r (\x -> Base.unsafeWrite x i e >> return (x,()))
65-} 65-}
66 66
67emptySTMRangeMap :: STM (RangeMap TArray Word8 TVar) 67emptySTMRangeMap :: STM (RangeMap TArray a TVar)
68emptySTMRangeMap = RefArray <$> 68emptySTMRangeMap = RefArray <$>
69 (newTVar =<< 69 (newTVar =<<
70 newListArray (0,-1) []) 70 newListArray (0,-1) [])
diff --git a/src/Network/Tox/Crypto/Handlers.hs b/src/Network/Tox/Crypto/Handlers.hs
index d5a49816..fabbf21d 100644
--- a/src/Network/Tox/Crypto/Handlers.hs
+++ b/src/Network/Tox/Crypto/Handlers.hs
@@ -32,7 +32,9 @@ import Data.Maybe
32import qualified Data.Word64Map as W64 32import qualified Data.Word64Map as W64
33import Data.Word64RangeMap 33import Data.Word64RangeMap
34import qualified Data.Set as Set 34import qualified Data.Set as Set
35import qualified Data.Array.Unboxed as A 35import qualified Data.Word64RangeMap.Unboxed as U
36import qualified Data.Array.Unboxed as U
37import qualified Data.Array as A
36import SensibleDir 38import SensibleDir
37import System.FilePath 39import System.FilePath
38import System.Environment 40import System.Environment
@@ -189,7 +191,7 @@ type NetCryptoHook = IOHook NetCryptoSession CryptoMessage
189-- | Convert an id byte to it's type (in Word64 format) 191-- | Convert an id byte to it's type (in Word64 format)
190-- Although the type doesn't enforce it, MsgTypeArray 192-- Although the type doesn't enforce it, MsgTypeArray
191-- should always have 256 entries. 193-- should always have 256 entries.
192type MsgTypeArray = A.UArray Word8 Word64 194type MsgTypeArray = U.UArray Word8 Word64
193 195
194-- | Information, that may be made visible in multiple sessions, as well 196-- | Information, that may be made visible in multiple sessions, as well
195-- as displayed in some way to the user via mutiple views. 197-- as displayed in some way to the user via mutiple views.
@@ -302,6 +304,9 @@ data NetCryptoSession = NCrypto
302 -- The remaining fields correspond to implementation specific state -- 304 -- The remaining fields correspond to implementation specific state --
303 -- where as the prior fields will be used in any implementation -- 305 -- where as the prior fields will be used in any implementation --
304 , ncHooks :: TVar (Map.Map MessageType [NetCryptoHook]) 306 , ncHooks :: TVar (Map.Map MessageType [NetCryptoHook])
307 , ncOutHooks :: RangeMap TArray
308 (TransportCrypto -> NetCryptoSession -> CryptoMessage -> IO (Either String (CryptoPacket Encrypted)))
309 TVar
305 , ncUnrecognizedHook :: TVar (MessageType -> NetCryptoHook) 310 , ncUnrecognizedHook :: TVar (MessageType -> NetCryptoHook)
306 , ncIdleEventHooks :: TVar [(Int,NetCryptoSession -> IO ())] 311 , ncIdleEventHooks :: TVar [(Int,NetCryptoSession -> IO ())]
307 , ncIncomingTypeArray :: TVar MsgTypeArray 312 , ncIncomingTypeArray :: TVar MsgTypeArray
@@ -315,7 +320,7 @@ data NetCryptoSession = NCrypto
315 -- always escapes. 320 -- always escapes.
316 -- 321 --
317 -- Currently, the values at these indices are ignored. 322 -- Currently, the values at these indices are ignored.
318 , ncOutgoingIdMap :: RangeMap TArray Word8 TVar 323 , ncOutgoingIdMap :: U.RangeMap TArray Word8 TVar
319 -- ^ used to lookup the outgoing id for a type when sending an outoing message 324 -- ^ used to lookup the outgoing id for a type when sending an outoing message
320 , ncOutgoingIdMapEscapedLossy :: TVar (A.Array Word8 Word8) 325 , ncOutgoingIdMapEscapedLossy :: TVar (A.Array Word8 Word8)
321 -- ^ mapping of secondary id, when primary id is 0xC7 326 -- ^ mapping of secondary id, when primary id is 0xC7
@@ -363,7 +368,7 @@ data NetCryptoSession = NCrypto
363 , ncOutgoingQueue :: TVar 368 , ncOutgoingQueue :: TVar
364 (UponHandshake 369 (UponHandshake
365 (PQ.PacketOutQueue 370 (PQ.PacketOutQueue
366 (State,Nonce24,RangeMap TArray Word8 TVar) 371 (State,Nonce24,U.RangeMap TArray Word8 TVar)
367 CryptoMessage 372 CryptoMessage
368 (CryptoPacket Encrypted) 373 (CryptoPacket Encrypted)
369 CryptoData)) 374 CryptoData))
@@ -495,7 +500,7 @@ type XMessage = CryptoMessage -- todo
495-- rangemap <- readTVar (ncOutgoingIdMap session) 500-- rangemap <- readTVar (ncOutgoingIdMap session)
496-- return (state,n24,rangemap) 501-- return (state,n24,rangemap)
497 502
498ncToWire :: STM (State,Nonce24,RangeMap TArray Word8 TVar) 503ncToWire :: STM (State,Nonce24,U.RangeMap TArray Word8 TVar)
499 -> Word32{- packet number we expect to recieve -} 504 -> Word32{- packet number we expect to recieve -}
500 -> Word32{- buffer_end -} 505 -> Word32{- buffer_end -}
501 -> Word32{- packet number -} 506 -> Word32{- packet number -}
@@ -512,7 +517,7 @@ ncToWire getState seqno bufend pktno msg = do
512 (state,n24,msgOutMapVar) <- getState 517 (state,n24,msgOutMapVar) <- getState
513 -- msgOutMap <- readTVar msgOutMapVar 518 -- msgOutMap <- readTVar msgOutMapVar
514 result1 <- dtrace XNetCrypto ("lookupInRangeMap typ64=" ++ show typ64 ++ " " ++ show typ ++ show msg) 519 result1 <- dtrace XNetCrypto ("lookupInRangeMap typ64=" ++ show typ64 ++ " " ++ show typ ++ show msg)
515 $ lookupInRangeMap typ64 msgOutMapVar 520 $ U.lookupInRangeMap typ64 msgOutMapVar
516 case result1 of -- msgOutMapLookup typ64 msgOutMap of 521 case result1 of -- msgOutMapLookup typ64 msgOutMap of
517 Nothing -> dtrace XNetCrypto "lookupInRangeMap gave Nothing!" $ return Nothing 522 Nothing -> dtrace XNetCrypto "lookupInRangeMap gave Nothing!" $ return Nothing
518 Just outid -> dtrace XNetCrypto ("encrypting packet with Nonce: " ++ show n24) $ do 523 Just outid -> dtrace XNetCrypto ("encrypting packet with Nonce: " ++ show n24) $ do
@@ -589,18 +594,26 @@ freshCryptoSession sessions
589 ncIdleEventHooks0 <- newTVar (defaultIdleEventHooks sessions) 594 ncIdleEventHooks0 <- newTVar (defaultIdleEventHooks sessions)
590 ncIncomingTypeArray0 <- newTVar (msgTypeArray sessions) 595 ncIncomingTypeArray0 <- newTVar (msgTypeArray sessions)
591 let idMap = foldl (\mp (x,y) -> W64.insert x y mp) W64.empty (zip [0..255] [0..255]) 596 let idMap = foldl (\mp (x,y) -> W64.insert x y mp) W64.empty (zip [0..255] [0..255])
592 (ncOutgoingIdMap0,lossyEscapeIdMap,losslessEscapeIdMap) <- do 597 (ncOutgoingIdMap0,lossyEscapeIdMap,losslessEscapeIdMap,ncOutHooks0) <- do
593 idmap <- emptySTMRangeMap 598 idmap <- U.emptySTMRangeMap
594 insertArrayAt idmap 0 (A.listArray (0,255) [0 .. 255]) 599 U.insertArrayAt idmap 0 (U.listArray (0,255) [0 .. 255])
595 -- the 2 escape ranges are adjacent, so put them in one array: 600 -- the 2 escape ranges are adjacent, so put them in one array:
596 insertArrayAt idmap 512 (A.listArray (512,1023) ( replicate 256 0xC7 -- lossy escaped 601 U.insertArrayAt idmap 512 (U.listArray (512,1023) ( replicate 256 0xC7 -- lossy escaped
597 ++ replicate 256 0x63 -- lossless escapped 602 ++ replicate 256 0x63 -- lossless escapped
598 )) 603 ))
599 -- lossless as separate range could have been done: 604 -- lossless as separate range could have been done:
600 -- > insertArrayAt idmap 768 (A.listArray (768,1023) (replicate 256 0x63)) 605 -- > insertArrayAt idmap 768 (A.listArray (768,1023) (replicate 256 0x63))
601 lossyEsc <- newTVar $ A.listArray (0,255) [0 .. 255] 606 lossyEsc <- newTVar $ U.listArray (0,255) [0 .. 255]
602 losslessEsc <- newTVar $ A.listArray (0,255) [0 .. 255] 607 losslessEsc <- newTVar $ U.listArray (0,255) [0 .. 255]
603 return (idmap,lossyEsc,losslessEsc) 608 outHooks <- emptySTMRangeMap
609 mapM_ ($ outHooks) -- TODO: combine into larger ranges for faster lookup
610 [ insertWhereItGoes (A.listArray (2,2) [sendKillHook])
611 , insertWhereItGoes (A.listArray (16,16) [sendLossless{-Ping-}])
612 , insertWhereItGoes (A.listArray (24,25) [sendOnlineHook,sendLossless{-Offline-}])
613 , insertWhereItGoes (A.listArray (48,51) [sendNickHook,sendStatusMsgHook,sendStatusHook,sendTypingHook])
614 , insertWhereItGoes (A.listArray (63,64) [sendMessageHook, sendMessageHook])
615 ]
616 return (idmap,lossyEsc,losslessEsc,outHooks)
604 ncView0 <- newTVar (sessionView sessions) 617 ncView0 <- newTVar (sessionView sessions)
605 pktq <- PQ.new (inboundQueueCapacity sessions) 0 618 pktq <- PQ.new (inboundQueueCapacity sessions) 0
606 bufstart <- newTVar 0 619 bufstart <- newTVar 0
@@ -645,6 +658,7 @@ freshCryptoSession sessions
645 , ncSessionSecret = newsession 658 , ncSessionSecret = newsession
646 , ncSockAddr = HaveDHTKey addr 659 , ncSockAddr = HaveDHTKey addr
647 , ncHooks = ncHooks0 660 , ncHooks = ncHooks0
661 , ncOutHooks = ncOutHooks0
648 , ncUnrecognizedHook = ncUnrecognizedHook0 662 , ncUnrecognizedHook = ncUnrecognizedHook0
649 , ncIdleEventHooks = ncIdleEventHooks0 663 , ncIdleEventHooks = ncIdleEventHooks0
650 , ncAllSessions = sessions 664 , ncAllSessions = sessions
@@ -677,13 +691,13 @@ freshCryptoSession sessions
677 HaveHandshake pktoq -> return (runUponHandshake netCryptoSession0 addr pktoq) 691 HaveHandshake pktoq -> return (runUponHandshake netCryptoSession0 addr pktoq)
678 return (myhandshake,maybeLaunchMissles) 692 return (myhandshake,maybeLaunchMissles)
679 693
680type NetCryptoOutQueue = PQ.PacketOutQueue (State,Nonce24,RangeMap TArray Word8 TVar) 694type NetCryptoOutQueue = PQ.PacketOutQueue (State,Nonce24,U.RangeMap TArray Word8 TVar)
681 CryptoMessage 695 CryptoMessage
682 (CryptoPacket Encrypted) 696 (CryptoPacket Encrypted)
683 CryptoData 697 CryptoData
684 698
685createNetCryptoOutQueue :: NetCryptoSessions -> SecretKey -> PublicKey -> PacketQueue CryptoData 699createNetCryptoOutQueue :: NetCryptoSessions -> SecretKey -> PublicKey -> PacketQueue CryptoData
686 -> TVar Nonce24 -> RangeMap TArray Word8 TVar -> STM (UponHandshake NetCryptoOutQueue) 700 -> TVar Nonce24 -> U.RangeMap TArray Word8 TVar -> STM (UponHandshake NetCryptoOutQueue)
687createNetCryptoOutQueue sessions newsession theirSessionKey pktq ncMyPacketNonce0 ncOutgoingIdMap0 = do 701createNetCryptoOutQueue sessions newsession theirSessionKey pktq ncMyPacketNonce0 ncOutgoingIdMap0 = do
688 let crypto = transportCrypto sessions 702 let crypto = transportCrypto sessions
689 let toWireIO = do 703 let toWireIO = do
@@ -1084,7 +1098,7 @@ sessionPacketH sessions addrRaw (CryptoPacket nonce16 encrypted) = do
1084 Nothing -> return () 1098 Nothing -> return ()
1085 msgTypes <- atomically $ readTVar ncIncomingTypeArray 1099 msgTypes <- atomically $ readTVar ncIncomingTypeArray
1086 let msgTyp = cd ^. messageType 1100 let msgTyp = cd ^. messageType
1087 msgTypMapped64 = msgTypes A.! fromEnum8 (msgID cm) 1101 msgTypMapped64 = msgTypes U.! fromEnum8 (msgID cm)
1088 msgTypMapped = fromWord64 $ msgTypMapped64 1102 msgTypMapped = fromWord64 $ msgTypMapped64
1089 isLossy (GrpMsg KnownLossy _) = True 1103 isLossy (GrpMsg KnownLossy _) = True
1090 isLossy (Msg mid) | lossyness mid == Lossy = True 1104 isLossy (Msg mid) | lossyness mid == Lossy = True
@@ -1116,7 +1130,7 @@ runCryptoHook session@(NCrypto {ncState, ncHooks,ncSessionSecret,ncTheirSessionP
1116 flip fix (cm,hookmap) $ \lookupAgain (cm,hookmap) -> do 1130 flip fix (cm,hookmap) $ \lookupAgain (cm,hookmap) -> do
1117 msgTypes <- atomically $ readTVar ncIncomingTypeArray 1131 msgTypes <- atomically $ readTVar ncIncomingTypeArray
1118 let msgTyp = cm ^. messageType 1132 let msgTyp = cm ^. messageType
1119 msgTypMapped64 = msgTypes A.! fromEnum8 (msgID cm) 1133 msgTypMapped64 = msgTypes U.! fromEnum8 (msgID cm)
1120 msgTypMapped = fromWord64 $ msgTypMapped64 1134 msgTypMapped = fromWord64 $ msgTypMapped64
1121 if msgTypMapped64 == 0 1135 if msgTypMapped64 == 0
1122 then return Nothing 1136 then return Nothing
@@ -1147,8 +1161,8 @@ runCryptoHook session@(NCrypto {ncState, ncHooks,ncSessionSecret,ncTheirSessionP
1147-- | construct a 'MsgTypeArray' for specified types, using their known common positions 1161-- | construct a 'MsgTypeArray' for specified types, using their known common positions
1148-- in the MessageId space if they have such a thing. 1162-- in the MessageId space if they have such a thing.
1149mkMsgTypes :: [MessageType] -> MsgTypeArray 1163mkMsgTypes :: [MessageType] -> MsgTypeArray
1150mkMsgTypes msgs = let zeros = A.listArray (0,255) (replicate 256 0) 1164mkMsgTypes msgs = let zeros = U.listArray (0,255) (replicate 256 0)
1151 in zeros A.// map (\x -> (toIndex x,toWord64 x)) msgs 1165 in zeros U.// map (\x -> (toIndex x,toWord64 x)) msgs
1152 where 1166 where
1153 toIndex (Msg mid) = fromIntegral . fromEnum $ mid 1167 toIndex (Msg mid) = fromIntegral . fromEnum $ mid
1154 toIndex (GrpMsg KnownLossless nam) = 0x63 -- fromEnum MESSAGE_GROUPCHAT 1168 toIndex (GrpMsg KnownLossless nam) = 0x63 -- fromEnum MESSAGE_GROUPCHAT
@@ -1189,10 +1203,10 @@ pattern PACKET_ID_LOSSY_RANGE_SIZE = 63
1189-- The first parameter is a function which is applied to get the values 1203-- The first parameter is a function which is applied to get the values
1190-- for keys of unknown nature. Could be either 'id' or 'const 0' 1204-- for keys of unknown nature. Could be either 'id' or 'const 0'
1191allMsgTypes :: (Word64 -> Word64) -> MsgTypeArray 1205allMsgTypes :: (Word64 -> Word64) -> MsgTypeArray
1192allMsgTypes fDefault = A.listArray (minBound,maxBound) (0:knownMsgs) 1206allMsgTypes fDefault = U.listArray (minBound,maxBound) (0:knownMsgs)
1193 where 1207
1194 knownMsgs :: [Word64] 1208knownMsgs :: [Word64]
1195 knownMsgs = 1209knownMsgs =
1196 concat [ map (fromIntegral . fromEnum) [ PacketRequest .. KillPacket ] 1210 concat [ map (fromIntegral . fromEnum) [ PacketRequest .. KillPacket ]
1197 , map (const 0) [ 3 .. 15 ] -- UnspecifiedPacket 1211 , map (const 0) [ 3 .. 15 ] -- UnspecifiedPacket
1198 , map (const 0) [ 16 .. 23 ] -- MessengerLoseless 1212 , map (const 0) [ 16 .. 23 ] -- MessengerLoseless
@@ -1236,6 +1250,10 @@ sendPing crypto session = do
1236sendOnline :: TransportCrypto -> NetCryptoSession -> IO (Either String (CryptoPacket Encrypted)) 1250sendOnline :: TransportCrypto -> NetCryptoSession -> IO (Either String (CryptoPacket Encrypted))
1237sendOnline crypto session = do 1251sendOnline crypto session = do
1238 let cm=OneByte ONLINE 1252 let cm=OneByte ONLINE
1253 sendOnlineHook crypto session cm
1254
1255sendOnlineHook :: TransportCrypto -> NetCryptoSession -> CryptoMessage -> IO (Either String (CryptoPacket Encrypted))
1256sendOnlineHook crypto session cm = do
1239 addMsgToLastN False (cm ^. messageType) session (Out cm) 1257 addMsgToLastN False (cm ^. messageType) session (Out cm)
1240 result <- sendCrypto crypto session (return ()) (OneByte ONLINE) 1258 result <- sendCrypto crypto session (return ()) (OneByte ONLINE)
1241 -- double this packet 1259 -- double this packet
@@ -1252,49 +1270,61 @@ sendOnline crypto session = do
1252sendOffline :: TransportCrypto -> NetCryptoSession -> IO (Either String (CryptoPacket Encrypted)) 1270sendOffline :: TransportCrypto -> NetCryptoSession -> IO (Either String (CryptoPacket Encrypted))
1253sendOffline crypto session = do 1271sendOffline crypto session = do
1254 let cm=OneByte OFFLINE 1272 let cm=OneByte OFFLINE
1273 sendLossless crypto session cm
1274
1275sendLossless :: TransportCrypto -> NetCryptoSession -> CryptoMessage -> IO (Either String (CryptoPacket Encrypted))
1276sendLossless crypto session cm = do
1255 addMsgToLastN False (cm ^. messageType) session (Out cm) 1277 addMsgToLastN False (cm ^. messageType) session (Out cm)
1256 sendCrypto crypto session (return ()) (OneByte OFFLINE) 1278 sendCrypto crypto session (return ()) (OneByte OFFLINE)
1257 1279
1280sendLossy :: TransportCrypto -> NetCryptoSession -> CryptoMessage -> IO (Either String (CryptoPacket Encrypted))
1281sendLossy crypto session cm = sendCryptoLossy crypto session (return ()) cm
1258 1282
1259sendKill :: TransportCrypto -> NetCryptoSession -> IO (Either String (CryptoPacket Encrypted)) 1283sendKill :: TransportCrypto -> NetCryptoSession -> IO (Either String (CryptoPacket Encrypted))
1260sendKill crypto session = do 1284sendKill crypto session = do
1261 let cm=OneByte KillPacket 1285 let cm=OneByte KillPacket
1286 sendKillHook crypto session cm
1287
1288sendKillHook :: TransportCrypto -> NetCryptoSession -> CryptoMessage -> IO (Either String (CryptoPacket Encrypted))
1289sendKillHook crypto session cm = sendCryptoLossy crypto session (destroySession session) cm
1290
1291sendCryptoLossy :: TransportCrypto -> NetCryptoSession -> (IO ()) -> CryptoMessage -> IO (Either String (CryptoPacket Encrypted))
1292sendCryptoLossy crypto session updateLocal cm = do
1262 mbOutQ <- atomically $ readTVar (ncOutgoingQueue session) 1293 mbOutQ <- atomically $ readTVar (ncOutgoingQueue session)
1263 case mbOutQ of 1294 case mbOutQ of
1264 NeedHandshake -> do 1295 NeedHandshake -> do
1265 let errmsg="NetCrypto NOT SENDING Kill packet (sessionid: " ++ show (ncSessionId session) ++ ") since no handshake yet" 1296 let errmsg = "Error sending lossy packet! (sessionid: " ++ show (ncSessionId session) ++ ") Need the Handshake first!"
1266 dput XNetCrypto errmsg 1297 updateLocal
1267 dput XNetCrypto $ "Destroying session anyway"
1268 destroySession session
1269 return (Left errmsg) 1298 return (Left errmsg)
1270 HaveHandshake outq -> do 1299 HaveHandshake outq -> do
1271 dput XNetCrypto $ "NetCrypto sending Kill packet (sessionid: " ++ show (ncSessionId session) ++ ")"
1272 getOutGoingParam <- PQ.readyOutGoing outq 1300 getOutGoingParam <- PQ.readyOutGoing outq
1273 mbPkt <- atomically $ PQ.peekPacket getOutGoingParam outq cm 1301 mbPkt <- atomically $ PQ.peekPacket getOutGoingParam outq cm
1274 case mbPkt of 1302 case mbPkt of
1275 Nothing -> do 1303 Nothing -> do
1276 let errmsg = "Error sending kill packet! (sessionid: " ++ show (ncSessionId session) ++ ")" 1304 let errmsg = "Error sending lossy packet! (sessionid: " ++ show (ncSessionId session) ++ ") " ++ show cm
1277 dput XNetCrypto errmsg 1305 updateLocal
1278 dput XNetCrypto $ "Destroying session anyway"
1279 Right <$> destroySession session
1280 return (Left errmsg) 1306 return (Left errmsg)
1281 Just (pkt,seqno) -> do 1307 Just (pkt,seqno) -> do
1282 case (ncSockAddr session) of 1308 case (ncSockAddr session) of
1283 NeedDHTKey -> do 1309 NeedDHTKey -> do
1284 let errmsg= "NetCrypto NOT SENDING Kill packet (sessionid: " ++ show (ncSessionId session) ++ ") since no DHTkey(sockaddr) yet" 1310 let errmsg= "NetCrypto NOT SENDING Lossy packet (sessionid: " ++ show (ncSessionId session) ++ ") since no DHTkey(sockaddr) yet"
1285 dput XNetCrypto errmsg 1311 updateLocal
1286 dput XNetCrypto $ "Destroying session anyway"
1287 Right <$> destroySession session
1288 return (Left errmsg) 1312 return (Left errmsg)
1289 HaveDHTKey saddr -> do 1313 HaveDHTKey saddr -> do
1290 sendSessionPacket (ncAllSessions session) saddr pkt 1314 sendSessionPacket (ncAllSessions session) saddr pkt
1291 dput XNetCrypto $ "sent kill packet (sessionid: " ++ show (ncSessionId session) ++ ")... now destroying session..." 1315 dput XNetCrypto $ "sent lossy packet (sessionid: " ++ show (ncSessionId session) ++ ") " ++ take 40 (show cm) ++ "..."
1292 destroySession session 1316 updateLocal
1293 return (Right pkt) 1317 return (Right pkt)
1294 1318
1295setNick :: TransportCrypto -> NetCryptoSession -> ByteString -> IO (Either String (CryptoPacket Encrypted)) 1319setNick :: TransportCrypto -> NetCryptoSession -> ByteString -> IO (Either String (CryptoPacket Encrypted))
1296setNick crypto session nick = do 1320setNick crypto session nick = do
1321 let cm = UpToN NICKNAME nick
1322 sendNickHook crypto session cm
1323
1324sendNickHook :: TransportCrypto -> NetCryptoSession -> CryptoMessage -> IO (Either String (CryptoPacket Encrypted))
1325sendNickHook crypto session cm = do
1297 let Just (_,maxlen) = msgSizeParam NICKNAME 1326 let Just (_,maxlen) = msgSizeParam NICKNAME
1327 let nick = msgBytes cm
1298 if B.length nick > maxlen 1328 if B.length nick > maxlen
1299 then return (Left $ "nickname must not exceed " ++ show maxlen ++ " bytes.") 1329 then return (Left $ "nickname must not exceed " ++ show maxlen ++ " bytes.")
1300 else do 1330 else do
@@ -1302,16 +1332,20 @@ setNick crypto session nick = do
1302 let viewVar = ncView session 1332 let viewVar = ncView session
1303 view <- readTVar viewVar 1333 view <- readTVar viewVar
1304 writeTVar (svNick view) nick 1334 writeTVar (svNick view) nick
1305 let cm = UpToN NICKNAME nick
1306 addMsgToLastN False (cm ^. messageType) session (Out cm) 1335 addMsgToLastN False (cm ^. messageType) session (Out cm)
1307 sendCrypto crypto session updateLocal cm 1336 sendCrypto crypto session updateLocal cm
1308 1337
1309setTyping :: TransportCrypto -> NetCryptoSession -> TypingStatus -> IO (Either String (CryptoPacket Encrypted)) 1338setTyping :: TransportCrypto -> NetCryptoSession -> TypingStatus -> IO (Either String (CryptoPacket Encrypted))
1310setTyping crypto session status = do 1339setTyping crypto session status = do
1340 let cm = TwoByte TYPING (fromEnum8 status)
1341 sendTypingHook crypto session cm
1342
1343sendTypingHook:: TransportCrypto -> NetCryptoSession -> CryptoMessage -> IO (Either String (CryptoPacket Encrypted))
1344sendTypingHook crypto session cm = do
1345 let status = toEnum8 (msgByte cm)
1311 let updateLocal = do 1346 let updateLocal = do
1312 view <- readTVar (ncView session) 1347 view <- readTVar (ncView session)
1313 writeTVar (svTyping view) status 1348 writeTVar (svTyping view) status
1314 let cm = TwoByte TYPING (fromEnum8 status)
1315 addMsgToLastN False (cm ^. messageType) session (Out cm) 1349 addMsgToLastN False (cm ^. messageType) session (Out cm)
1316 sendCrypto crypto session updateLocal cm 1350 sendCrypto crypto session updateLocal cm
1317 1351
@@ -1325,36 +1359,51 @@ setNoSpam crypto session mbnospam = do
1325 1359
1326setStatus :: TransportCrypto -> NetCryptoSession -> UserStatus -> IO (Either String (CryptoPacket Encrypted)) 1360setStatus :: TransportCrypto -> NetCryptoSession -> UserStatus -> IO (Either String (CryptoPacket Encrypted))
1327setStatus crypto session status = do 1361setStatus crypto session status = do
1362 let cm = TwoByte USERSTATUS (fromEnum8 status)
1363 sendStatusHook crypto session cm
1364
1365sendStatusHook :: TransportCrypto -> NetCryptoSession -> CryptoMessage -> IO (Either String (CryptoPacket Encrypted))
1366sendStatusHook crypto session cm = do
1367 let status = toEnum8 (msgByte cm)
1328 let updateLocal = do 1368 let updateLocal = do
1329 view <- readTVar (ncView session) 1369 view <- readTVar (ncView session)
1330 writeTVar (svStatus view) status 1370 writeTVar (svStatus view) status
1331 let cm = TwoByte USERSTATUS (fromEnum8 status)
1332 addMsgToLastN False (cm ^. messageType) session (Out cm) 1371 addMsgToLastN False (cm ^. messageType) session (Out cm)
1333 sendCrypto crypto session updateLocal cm 1372 sendCrypto crypto session updateLocal cm
1334 1373
1335setStatusMsg :: TransportCrypto -> NetCryptoSession -> ByteString -> IO (Either String (CryptoPacket Encrypted)) 1374setStatusMsg :: TransportCrypto -> NetCryptoSession -> ByteString -> IO (Either String (CryptoPacket Encrypted))
1336setStatusMsg crypto session msg = do 1375setStatusMsg crypto session msg = do
1376 let cm = UpToN STATUSMESSAGE msg
1377 sendStatusMsgHook crypto session cm
1378
1379sendStatusMsgHook :: TransportCrypto -> NetCryptoSession -> CryptoMessage -> IO (Either String (CryptoPacket Encrypted))
1380sendStatusMsgHook crypto session cm = do
1337 let Just (_,maxlen) = msgSizeParam STATUSMESSAGE 1381 let Just (_,maxlen) = msgSizeParam STATUSMESSAGE
1382 let msg = msgBytes cm
1338 if B.length msg > maxlen 1383 if B.length msg > maxlen
1339 then return (Left $ "status message must not exceed " ++ show maxlen ++ " bytes.") 1384 then return (Left $ "status message must not exceed " ++ show maxlen ++ " bytes.")
1340 else do 1385 else do
1341 let updateLocal = do 1386 let updateLocal = do
1342 view <- readTVar (ncView session) 1387 view <- readTVar (ncView session)
1343 writeTVar (svStatusMsg view) msg 1388 writeTVar (svStatusMsg view) msg
1344 let cm = UpToN STATUSMESSAGE msg
1345 addMsgToLastN False (cm ^. messageType) session (Out cm) 1389 addMsgToLastN False (cm ^. messageType) session (Out cm)
1346 sendCrypto crypto session updateLocal cm 1390 sendCrypto crypto session updateLocal cm
1347 1391
1348sendChatMsg :: TransportCrypto -> NetCryptoSession -> ByteString -> IO (Either String (CryptoPacket Encrypted)) 1392sendChatMsg :: TransportCrypto -> NetCryptoSession -> ByteString -> IO (Either String (CryptoPacket Encrypted))
1349sendChatMsg crypto session msg = do 1393sendChatMsg crypto session msg = do
1394 let cm = UpToN MESSAGE msg
1395 sendMessageHook crypto session cm
1396
1397sendMessageHook :: TransportCrypto -> NetCryptoSession -> CryptoMessage -> IO (Either String (CryptoPacket Encrypted))
1398sendMessageHook crypto session cm = do
1350 let Just (_,maxlen) = msgSizeParam MESSAGE 1399 let Just (_,maxlen) = msgSizeParam MESSAGE
1400 let msg = msgBytes cm
1351 if B.length msg > maxlen 1401 if B.length msg > maxlen
1352 then return (Left $ "status message must not exceed " ++ show maxlen ++ " bytes.") 1402 then return (Left $ "status message must not exceed " ++ show maxlen ++ " bytes.")
1353 else do 1403 else do
1354 let updateLocal = do 1404 let updateLocal = do
1355 view <- readTVar (ncView session) 1405 view <- readTVar (ncView session)
1356 writeTVar (svStatusMsg view) msg 1406 writeTVar (svStatusMsg view) msg
1357 let cm = UpToN MESSAGE msg
1358 addMsgToLastN False (cm ^. messageType) session (Out cm) 1407 addMsgToLastN False (cm ^. messageType) session (Out cm)
1359 sendCrypto crypto session updateLocal cm 1408 sendCrypto crypto session updateLocal cm
1360 1409