summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2018-09-08 04:31:51 -0400
committerJoe Crayne <joe@jerkface.net>2018-09-08 06:05:10 -0400
commitad20be57786ad34f80192206c480d575392b4ebb (patch)
tree722333a152705572f7437586772a9173e84a92e2
parente5add92a477060d9bba10de7b980c89c24012691 (diff)
ToxManager rewrite: use aggregated netcrypto sessions.
-rw-r--r--ToxManager.hs209
-rw-r--r--dht-client.cabal2
-rw-r--r--examples/dhtd.hs83
-rw-r--r--src/Network/Tox.hs11
4 files changed, 240 insertions, 65 deletions
diff --git a/ToxManager.hs b/ToxManager.hs
index cfdb4f50..78049010 100644
--- a/ToxManager.hs
+++ b/ToxManager.hs
@@ -9,10 +9,10 @@ module ToxManager where
9import Announcer 9import Announcer
10import Announcer.Tox 10import Announcer.Tox
11import ClientState 11import ClientState
12import Connection
13import Control.Concurrent.STM 12import Control.Concurrent.STM
14import Control.Monad 13import Control.Monad
15import Crypto.Tox 14import Crypto.Tox
15import qualified Data.ByteArray as BA
16import Data.Bits 16import Data.Bits
17import Data.Function 17import Data.Function
18import qualified Data.HashMap.Strict as HashMap 18import qualified Data.HashMap.Strict as HashMap
@@ -24,6 +24,8 @@ import qualified Data.Text as T
24import Data.Time.Clock.POSIX 24import Data.Time.Clock.POSIX
25import Data.Word 25import Data.Word
26import DPut 26import DPut
27import Foreign.Storable
28import HandshakeCache
27import Network.Address 29import Network.Address
28import qualified Network.Kademlia.Routing as R 30import qualified Network.Kademlia.Routing as R
29 ;import Network.Kademlia.Routing as R 31 ;import Network.Kademlia.Routing as R
@@ -31,9 +33,9 @@ import Network.Kademlia.Search
31import Network.QueryResponse 33import Network.QueryResponse
32import qualified Network.Tox as Tox 34import qualified Network.Tox as Tox
33 ;import Network.Tox 35 ;import Network.Tox
36import Network.Tox.AggregateSession
34import Network.Tox.ContactInfo as Tox 37import Network.Tox.ContactInfo as Tox
35import qualified Network.Tox.Crypto.Handlers as Tox 38import qualified Network.Tox.Crypto.Handlers as Tox
36 ;import Network.Tox.Crypto.Handlers (UponCookie (..))
37import Network.Tox.DHT.Handlers (nodeSearch, nodesOfInterest) 39import Network.Tox.DHT.Handlers (nodeSearch, nodesOfInterest)
38import Network.Tox.DHT.Handlers 40import Network.Tox.DHT.Handlers
39import qualified Network.Tox.DHT.Transport as Tox 41import qualified Network.Tox.DHT.Transport as Tox
@@ -53,7 +55,8 @@ import Control.Concurrent.Lifted.Instrument
53import Control.Concurrent.Lifted 55import Control.Concurrent.Lifted
54import GHC.Conc (labelThread) 56import GHC.Conc (labelThread)
55#endif 57#endif
56 58import GHC.Conc (unsafeIOToSTM)
59import Connection
57 60
58 61
59toxAnnounceSendData :: Tox.Tox JabberClients 62toxAnnounceSendData :: Tox.Tox JabberClients
@@ -84,12 +87,13 @@ stringToKey_ s = let (xs,ys) = break (==':') s
84-- 87--
85-- These hooks will be invoked in order to connect to *.tox hosts in a user's 88-- These hooks will be invoked in order to connect to *.tox hosts in a user's
86-- XMPP roster. 89-- XMPP roster.
87toxman :: Announcer 90toxman :: TVar (Map.Map Uniq24 AggregateSession)
91 -> Announcer
88 -> [(String,TVar (BucketList Tox.NodeInfo))] 92 -> [(String,TVar (BucketList Tox.NodeInfo))]
89 -> Tox.Tox JabberClients 93 -> Tox.Tox JabberClients
90 -> PresenceState 94 -> PresenceState
91 -> ToxManager ClientAddress 95 -> ToxManager ClientAddress
92toxman announcer toxbkts tox presence = ToxManager 96toxman ssvar announcer toxbkts tox presence = ToxManager
93 { activateAccount = \k pubname seckey -> do 97 { activateAccount = \k pubname seckey -> do
94 dput XMan $ "toxman ACTIVATE " ++ show (Tox.key2id $ toPublic seckey) 98 dput XMan $ "toxman ACTIVATE " ++ show (Tox.key2id $ toPublic seckey)
95 let ContactInfo{ accounts } = Tox.toxContactInfo tox 99 let ContactInfo{ accounts } = Tox.toxContactInfo tox
@@ -123,7 +127,7 @@ toxman announcer toxbkts tox presence = ToxManager
123 toxAnnounceInterval) 127 toxAnnounceInterval)
124 pub 128 pub
125 129
126 forkAccountWatcher acnt tox presence announcer 130 forkAccountWatcher ssvar acnt tox presence announcer
127 return () 131 return ()
128 132
129 , deactivateAccount = \k pubname -> do 133 , deactivateAccount = \k pubname -> do
@@ -168,23 +172,39 @@ toxman announcer toxbkts tox presence = ToxManager
168 Just acc -> setContactPolicy (Tox.id2key themid) TryingToConnect acc 172 Just acc -> setContactPolicy (Tox.id2key themid) TryingToConnect acc
169 -- If unscheduled and unconnected, schedule recurring search for this contact. 173 -- If unscheduled and unconnected, schedule recurring search for this contact.
170 _ -> return () -- Remove contact. 174 _ -> return () -- Remove contact.
171 , connections = _todo 175 , connections = do
176 let ContactInfo{ accounts } = Tox.toxContactInfo tox
177 as <- HashMap.toList <$> readTVar accounts
178 fmap concat $ forM as $ \(me,a) -> do
179 ks <- HashMap.keys <$> readTVar (contacts a)
180 return $ map (ToxContact me) ks
181 , status = \(ToxContact me them) -> do
182 ma <- HashMap.lookup me <$> readTVar (accounts $ Tox.toxContactInfo tox)
183 fmap (fromMaybe (Connection Dormant RefusingToConnect)) $ forM ma $ \a -> do
184 mc <- getContact (id2key them) a
185 let mek = id2key me
186 themk = id2key them
187 u <- xor24 <$> unsafeIOToSTM (hash24 mek) <*> unsafeIOToSTM (hash24 themk)
188 ag <- do ag <- Map.lookup u <$> readTVar ssvar
189 maybe (return Nothing)
190 (\c -> checkCompatible mek themk c >>= \case
191 Just False -> return Nothing
192 _ -> return ag)
193 ag
194 s <- getStatus mek themk ag mc (toxHandshakeCache tox)
195 mp <- join <$> mapM (readTVar . contactPolicy) mc
196 return $ Connection s (fromMaybe RefusingToConnect mp)
172 , stringToKey = stringToKey_ 197 , stringToKey = stringToKey_
173 , showProgress = show 198 , showProgress = show
174 , showKey = show 199 , showKey = show
175 } 200 }
176 , resolveToxPeer = \me them -> do 201 , resolveToxPeer = \me them -> do
177 let lookupContact accs 202 let m = do meid <- readMaybe $ T.unpack me
178 = do meid <- readMaybe $ T.unpack me 203 themid <- readMaybe $ T.unpack them
179 themid <- readMaybe $ T.unpack them 204 return (id2key meid, id2key themid)
180 acc <- HashMap.lookup meid accs 205 forM m $ \(me,them) -> do
181 return $ HashMap.lookup themid <$> readTVar (contacts acc) 206 u <- xor24 <$> hash24 me <*> hash24 them
182 atomically $ do 207 return $ addrToPeerKey $ Remote $ uniqueAsKey u
183 accs <- let ContactInfo{ accounts } = Tox.toxContactInfo tox
184 in readTVar accounts
185 mc <- join <$> sequence (lookupContact accs)
186 maddr <- join <$> mapM (readTVar . contactLastSeenAddr) mc
187 return $ addrToPeerKey . Remote . Tox.nodeAddr . snd <$> maddr
188 } 208 }
189 209
190key2jid :: Word32 -> PublicKey -> Text 210key2jid :: Word32 -> PublicKey -> Text
@@ -209,10 +229,11 @@ initPerClient = do
209 } 229 }
210 230
211data ToxToXMPP = ToxToXMPP 231data ToxToXMPP = ToxToXMPP
212 { txAnnouncer :: Announcer 232 { txAnnouncer :: Announcer
213 , txAccount :: Account JabberClients 233 , txAccount :: Account JabberClients
214 , txPresence :: PresenceState 234 , txPresence :: PresenceState
215 , txTox :: Tox JabberClients 235 , txTox :: Tox JabberClients
236 , txSessions :: TVar (Map.Map Uniq24 AggregateSession)
216 } 237 }
217 238
218default_nospam :: Word32 239default_nospam :: Word32
@@ -316,26 +337,40 @@ gotAddr' ni@(nodeAddr -> addr) tx theirKey theirDhtKey = atomically blee
316 tox :: Tox JabberClients 337 tox :: Tox JabberClients
317 tox = txTox tx 338 tox = txTox tx
318 339
340 crypto = toxCryptoKeys tox
341
342 {-
319 byAddr :: TVar (Map.Map SockAddr Tox.NetCryptoSession) 343 byAddr :: TVar (Map.Map SockAddr Tox.NetCryptoSession)
320 byAddr = Tox.netCryptoSessions (toxCryptoSessions tox) 344 byAddr = Tox.netCryptoSessions (toxCryptoSessions tox)
321 345
322 crypto = Tox.transportCrypto $ toxCryptoSessions tox
323
324 readNcVar :: (Tox.NetCryptoSession -> TVar b) -> SockAddr -> STM (Maybe b) 346 readNcVar :: (Tox.NetCryptoSession -> TVar b) -> SockAddr -> STM (Maybe b)
325 readNcVar v addr = traverse readTVar =<< fmap v . Map.lookup addr <$> readTVar byAddr 347 readNcVar v addr = traverse readTVar =<< fmap v . Map.lookup addr <$> readTVar byAddr
326 348 -}
327 chillSesh :: SockAddr -> STM (Maybe (Status Tox.ToxProgress))
328 chillSesh = readNcVar Tox.ncState
329 349
330 activeSesh :: SockAddr -> STM Bool 350 activeSesh :: SockAddr -> STM Bool
331 activeSesh a = chillSesh a >>= return . \case 351 activeSesh a = do
332 Just Established -> True 352 ss <- readTVar (txSessions tx)
333 _ -> False 353 u <- xor24 <$> unsafeIOToSTM (hash24 myPublicKey)
334 354 <*> unsafeIOToSTM (hash24 theirKey)
355 case Map.lookup u ss of
356 Nothing -> return False
357 -- TODO: Currently we consider the session active if it is actually established.
358 -- Perhaps it would be better to also consider it "active" when an incompatible
359 -- session is holding the Uniq24 slot in txSessions because the connection will
360 -- ultimately fail anyway in that case. Alternatively, we could drop the Uniq24
361 -- map and use a full (PublicKey,PublicKey) key, but this would require changing
362 -- how XMPP connections are handled since they are currently distinguished by a
363 -- SockAddr which cannot hold more than a 24-byte key. (See XMPPServer.peerKey).
364 Just c -> checkCompatible myPublicKey theirKey c >>= \case
365 Just False -> return False
366 _ -> (== Established) <$> aggregateStatus c
367
368 {-
335 readCookie :: SockAddr -> STM (Maybe (UponCookie (Tox.Cookie Encrypted))) 369 readCookie :: SockAddr -> STM (Maybe (UponCookie (Tox.Cookie Encrypted)))
336 readCookie = readNcVar Tox.ncCookie 370 readCookie = readNcVar Tox.ncCookie
337 readCookie' :: SockAddr -> STM (Maybe (Tox.Cookie Encrypted)) 371 readCookie' :: SockAddr -> STM (Maybe (Tox.Cookie Encrypted))
338 readCookie' = fmap join . (fmap.fmap) Tox.toMaybe . readCookie 372 readCookie' = fmap join . (fmap.fmap) Tox.toMaybe . readCookie
373 -}
339 374
340 client :: Network.Tox.DHT.Handlers.Client 375 client :: Network.Tox.DHT.Handlers.Client
341 client = toxDHT tox 376 client = toxDHT tox
@@ -359,7 +394,15 @@ gotAddr' ni@(nodeAddr -> addr) tx theirKey theirDhtKey = atomically blee
359 active <- isActive 394 active <- isActive
360 return $ when (not active) getCookieIO 395 return $ when (not active) getCookieIO
361 396
362 callRealShakeHands = realShakeHands (userSecret (txAccount tx)) theirKey (dhtpk theirDhtKey) (toxCryptoSessions tox) (nodeAddr ni) 397 callRealShakeHands cookie = do
398 {-
399 forM_ (nodeInfo (key2id $ dhtpk theirDhtKey) (nodeAddr ni)) $ \ni' -> do
400 hs <- cacheHandshake (toxHandshakeCache tox) (userSecret (txAccount tx)) theirKey ni' cookie
401 dput XNetCrypto $ show addr ++ "<-- handshake " ++ show (key2id theirKey)
402 sendMessage (toxHandshakes tox) (nodeAddr ni) hs
403 -}
404 realShakeHands (userSecret (txAccount tx)) theirKey (dhtpk theirDhtKey) (toxCryptoSessions tox) (nodeAddr ni) cookie
405
363 406
364 reschedule n f = scheduleRel ann akey f n 407 reschedule n f = scheduleRel ann akey f n
365 reschedule' n f = reschedule n (ScheduledItem $ \_ _ now -> f now) 408 reschedule' n f = reschedule n (ScheduledItem $ \_ _ now -> f now)
@@ -368,10 +411,16 @@ gotAddr' ni@(nodeAddr -> addr) tx theirKey theirDhtKey = atomically blee
368 411
369 getCookieIO :: IO () 412 getCookieIO :: IO ()
370 getCookieIO = do 413 getCookieIO = do
371 dput XUnused "getCookieIO - entered" 414 dput XNetCrypto $ show addr ++ " <-- request cookie"
415 let pending flag = setPendingCookie (toxHandshakeCache tox) myPublicKey theirKey flag
416 atomically $ pending True
372 cookieRequest crypto client myPublicKey ni >>= \case 417 cookieRequest crypto client myPublicKey ni >>= \case
373 Nothing -> atomically $ reschedule' 5 (const getCookieAgain) 418 Nothing -> atomically $ do
419 pending False
420 reschedule' 5 (const getCookieAgain)
374 Just cookie -> do 421 Just cookie -> do
422 dput XNetCrypto $ show addr ++ "--> cookie"
423 atomically $ pending False
375 void $ callRealShakeHands cookie 424 void $ callRealShakeHands cookie
376 cookieCreationStamp <- getPOSIXTime 425 cookieCreationStamp <- getPOSIXTime
377 let shaker :: POSIXTime -> STM (IO ()) 426 let shaker :: POSIXTime -> STM (IO ())
@@ -388,6 +437,7 @@ gotAddr' ni@(nodeAddr -> addr) tx theirKey theirDhtKey = atomically blee
388 return . void $ callRealShakeHands cookie 437 return . void $ callRealShakeHands cookie
389 atomically $ reschedule' 5 shaker 438 atomically $ reschedule' 5 shaker
390 439
440
391realShakeHands :: SecretKey -> PublicKey -> PublicKey -> Tox.NetCryptoSessions -> SockAddr -> Tox.Cookie Encrypted -> IO Bool 441realShakeHands :: SecretKey -> PublicKey -> PublicKey -> Tox.NetCryptoSessions -> SockAddr -> Tox.Cookie Encrypted -> IO Bool
392realShakeHands myseckey theirpubkey theirDhtKey allsessions saddr cookie = do 442realShakeHands myseckey theirpubkey theirDhtKey allsessions saddr cookie = do
393 dput XUnused "realShakeHands" 443 dput XUnused "realShakeHands"
@@ -409,6 +459,8 @@ realShakeHands myseckey theirpubkey theirDhtKey allsessions saddr cookie = do
409 -- send handshake 459 -- send handshake
410 isJust <$> forM myhandshake (Tox.sendHandshake allsessions saddr) 460 isJust <$> forM myhandshake (Tox.sendHandshake allsessions saddr)
411 461
462
463
412dispatch :: ToxToXMPP -> ContactEvent -> IO () 464dispatch :: ToxToXMPP -> ContactEvent -> IO ()
413dispatch tx (SessionEstablished theirKey) = stopConnecting tx theirKey "established" 465dispatch tx (SessionEstablished theirKey) = stopConnecting tx theirKey "established"
414dispatch tx (SessionTerminated theirKey) = startConnecting tx theirKey "terminated" 466dispatch tx (SessionTerminated theirKey) = startConnecting tx theirKey "terminated"
@@ -524,24 +576,20 @@ startConnecting0 tx them contact reason = do
524 dkey <- Tox.getContactInfo tox 576 dkey <- Tox.getContactInfo tox
525 let tr = Tox.toxToRoute tox 577 let tr = Tox.toxToRoute tox
526 route = Tox.AnnouncedRendezvous theirkey rendezvous 578 route = Tox.AnnouncedRendezvous theirkey rendezvous
527 dput XMan $ unwords [ take 8 (show $ key2id mypub) ++ ":" 579 dput XMan $ unwords [ take 8 (show $ key2id theirkey)
528 , "Sending my DHT-key" 580 , show (nodeAddr $ Tox.rendezvousNode rendezvous)
529 , show (key2id $ Tox.dhtpk dkey) 581 , "<--"
530 , "to" 582 , "DHTKey"
531 , show (key2id theirkey) 583 , take 8 (show $ key2id mypub) ++ "/"
532 , "via" 584 ++ take 8 (show $ key2id $ Tox.dhtpk dkey)
533 , show (Tox.rendezvousNode rendezvous)
534 ] 585 ]
535 sendMessage tr route (mypub,Tox.OnionDHTPublicKey dkey) 586 sendMessage tr route (mypub,Tox.OnionDHTPublicKey dkey)
536 forM_ soliciting $ \cksum@(NoSpam nospam _)-> do 587 forM_ soliciting $ \cksum@(NoSpam nospam _)-> do
537 dput XMan $ unwords [ take 8 (show $ key2id mypub) ++ ":" 588 dput XMan $ unwords [ take 8 (show $ key2id theirkey)
538 , "Sending friend-request" 589 , show (nodeAddr $ Tox.rendezvousNode rendezvous)
539 , "with nospam" 590 , "<-- FriendRequest"
540 , "(" ++ nospam64 cksum ++ "," ++nospam16 cksum ++ ")" 591 , take 8 (show $ key2id mypub)
541 , "to" 592 , "nospam=" ++ "(" ++ nospam64 cksum ++ "," ++nospam16 cksum ++ ")"
542 , show (key2id theirkey)
543 , "via"
544 , show (Tox.rendezvousNode rendezvous)
545 ] 593 ]
546 let fr = FriendRequest 594 let fr = FriendRequest
547 { friendNoSpam = nospam 595 { friendNoSpam = nospam
@@ -559,7 +607,7 @@ startConnecting tx them reason = do
559 607
560stopConnecting :: ToxToXMPP -> PublicKey -> String -> IO () 608stopConnecting :: ToxToXMPP -> PublicKey -> String -> IO ()
561stopConnecting ToxToXMPP{txAnnouncer=announcer,txAccount=acnt} them reason = do 609stopConnecting ToxToXMPP{txAnnouncer=announcer,txAccount=acnt} them reason = do
562 dput XMan $ "STOP CONNECTING " ++ show (key2id them) ++ "("++reason++")" 610 dput XMan $ "STOP("++reason++") CONNECTING " ++ show (key2id them)
563 let pub = toPublic $ userSecret acnt 611 let pub = toPublic $ userSecret acnt
564 me = key2id pub 612 me = key2id pub
565 akeyC = akeyConnect announcer me them 613 akeyC = akeyConnect announcer me them
@@ -567,18 +615,20 @@ stopConnecting ToxToXMPP{txAnnouncer=announcer,txAccount=acnt} them reason = do
567 cancel announcer akeyC 615 cancel announcer akeyC
568 cancel announcer akeyD 616 cancel announcer akeyD
569 617
570forkAccountWatcher :: Account JabberClients -> Tox JabberClients -> PresenceState -> Announcer -> IO ThreadId 618forkAccountWatcher :: TVar (Map.Map Uniq24 AggregateSession)
571forkAccountWatcher acc tox st announcer = forkIO $ do 619 -> Account JabberClients -> Tox JabberClients -> PresenceState -> Announcer -> IO ThreadId
572 myThreadId >>= flip labelThread ("tox-xmpp:" 620forkAccountWatcher ssvar acc tox st announcer = forkIO $ do
621 myThreadId >>= flip labelThread ("online:"
573 ++ show (key2id $ toPublic $ userSecret acc)) 622 ++ show (key2id $ toPublic $ userSecret acc))
574 (chan,cs) <- atomically $ do 623 (chan,cs) <- atomically $ do
575 chan <- dupTChan $ eventChan acc -- duplicate broadcast channel for reading. 624 chan <- dupTChan $ eventChan acc -- duplicate broadcast channel for reading.
576 contacts <- readTVar (contacts acc) 625 contacts <- readTVar (contacts acc)
577 return (chan,contacts) 626 return (chan,contacts)
578 let tx = ToxToXMPP { txAnnouncer = announcer 627 let tx = ToxToXMPP { txAnnouncer = announcer
579 , txAccount = acc 628 , txAccount = acc
580 , txPresence = st 629 , txPresence = st
581 , txTox = tox 630 , txTox = tox
631 , txSessions = ssvar
582 } 632 }
583 forM_ (HashMap.toList cs) $ \(them,c) -> do 633 forM_ (HashMap.toList cs) $ \(them,c) -> do
584 startConnecting0 tx (id2key them) c "enabled account" 634 startConnecting0 tx (id2key them) c "enabled account"
@@ -597,13 +647,48 @@ forkAccountWatcher acc tox st announcer = forkIO $ do
597 cs <- atomically $ readTVar (contacts acc) 647 cs <- atomically $ readTVar (contacts acc)
598 forM_ (HashMap.toList cs) $ \(them,c) -> do 648 forM_ (HashMap.toList cs) $ \(them,c) -> do
599 stopConnecting tx (id2key them) "disabled account" 649 stopConnecting tx (id2key them) "disabled account"
650 -- TODO: closeAll for each relevant session in ssvar.
600 651
601 652
602toxQSearch :: Tox extra -> Search Tox.NodeId (IP, PortNumber) Nonce32 Tox.NodeInfo Tox.Rendezvous
603toxQSearch tox = Tox.toxidSearch (Tox.onionTimeout tox) (Tox.toxCryptoKeys tox) (Tox.toxOnion tox)
604
605toxAnnounceInterval :: POSIXTime 653toxAnnounceInterval :: POSIXTime
606toxAnnounceInterval = 15 654toxAnnounceInterval = 15
607 655
608 656getStatus :: PublicKey -> PublicKey -> Maybe AggregateSession -> Maybe Contact -> HandshakeCache -> STM (Status ToxProgress)
609 657getStatus me them a c hs = do
658 astat <- maybe (return Dormant) aggregateStatus a
659 policy <- fromMaybe RefusingToConnect <$> maybe (return Nothing) (readTVar . contactPolicy) c
660 mdht <- maybe (return Nothing) (readTVar . contactKeyPacket) c
661 maddr <- maybe (return Nothing) (readTVar . contactLastSeenAddr) c
662 haveCookie <- haveCachedCookie hs me them
663 return $ statusLogic astat policy mdht maddr haveCookie
664
665statusLogic :: Status ToxProgress -> Policy -> Maybe dhtkey -> Maybe addr -> Bool -> Status ToxProgress
666statusLogic astat policy mdht maddr haveCookie = case () of
667 () | Established <- astat -> Established
668 | InProgress AwaitingSessionPacket <- astat -> InProgress AwaitingSessionPacket
669 | RefusingToConnect <- policy -> Dormant
670 | Nothing <- mdht -> InProgress AwaitingDHTKey
671 | Nothing <- maddr -> InProgress AcquiringIPAddress
672 | not haveCookie -> InProgress AcquiringCookie
673 | otherwise -> InProgress AwaitingHandshake
674
675
676hash24 :: BA.ByteArrayAccess ba => ba -> IO Uniq24
677hash24 them | let r = 32 - BA.length them, (r > 0)
678 = hash24 $ BA.append (BA.convert them :: BA.Bytes)
679 (BA.replicate r 0) -- XXX: It'd be better to insert ahead of last 8 bytes.
680hash24 them = BA.withByteArray them $ \p -> do
681 x <- peek p
682 y <- peekElemOff p 1
683 -- skipping word64 2
684 z <- peekElemOff p 3
685 return $! Uniq24 x y z
686
687xor24 :: Uniq24 -> Uniq24 -> Uniq24
688xor24 (Uniq24 xa xb xc) (Uniq24 ya yb yc) =
689 Uniq24 (xor xa ya) (xor xb yb) (xor xc yc)
690
691
692
693-- 321
694-- 357
diff --git a/dht-client.cabal b/dht-client.cabal
index bddb07b3..0eef7cee 100644
--- a/dht-client.cabal
+++ b/dht-client.cabal
@@ -146,6 +146,8 @@ library
146 ToxManager 146 ToxManager
147 XMPPToTox 147 XMPPToTox
148 DebugUtil 148 DebugUtil
149 HandshakeCache
150 Network.Tox.AggregateSession
149 151
150 build-depends: base 152 build-depends: base
151 , containers 153 , containers
diff --git a/examples/dhtd.hs b/examples/dhtd.hs
index db8664e8..34b555f5 100644
--- a/examples/dhtd.hs
+++ b/examples/dhtd.hs
@@ -31,6 +31,7 @@ import Data.Array.MArray (getAssocs)
31import Data.Bool 31import Data.Bool
32import Data.Char 32import Data.Char
33import Data.Conduit as C 33import Data.Conduit as C
34import qualified Data.Conduit.List as C
34import Data.Function 35import Data.Function
35import Data.Hashable 36import Data.Hashable
36import Data.List 37import Data.List
@@ -105,6 +106,7 @@ import Network.Tox.ContactInfo as Tox
105import OnionRouter 106import OnionRouter
106import Data.PacketQueue 107import Data.PacketQueue
107import qualified Data.Word64Map as W64 108import qualified Data.Word64Map as W64
109import Network.Tox.AggregateSession
108import System.FilePath 110import System.FilePath
109import System.Process 111import System.Process
110import System.Posix.IO 112import System.Posix.IO
@@ -1622,6 +1624,71 @@ showMsg (n,(flg,(snapshot,iocm))) = B.concat [bool " " "h " flg, showmsg' (snap
1622 _ | o <= 122 && o >= 97 -> chr (o + 119737) 1624 _ | o <= 122 && o >= 97 -> chr (o + 119737)
1623 _ -> x 1625 _ -> x
1624 1626
1627onNewToxSession :: XMPPServer
1628 -> TVar (Map.Map Uniq24 AggregateSession)
1629 -> ContactInfo extra
1630 -> SockAddr
1631 -> Tox.NetCryptoSession
1632 -> IO ()
1633onNewToxSession sv ssvar ContactInfo{accounts} addrTox netcrypto = do
1634 let them s = Tox.ncTheirPublicKey s
1635
1636 me s = Tox.ncMyPublicKey s
1637
1638 onStatusChange :: (Tox.NetCryptoSession -> Tcp.ConnectionEvent XML.Event -> STM ())
1639 -> AggregateSession -> Tox.NetCryptoSession -> Status Tox.ToxProgress -> STM ()
1640 onStatusChange announce c s Established = onConnect announce c s
1641 onStatusChange announce _ s _ = onEOF announce s
1642
1643 onEOF announce s = do
1644 HashMap.lookup (Tox.key2id $ me s) <$> readTVar accounts
1645 >>= mapM_ (setTerminated $ them s)
1646 announce s Tcp.EOF
1647
1648 onConnect announce c s = do
1649 HashMap.lookup (Tox.key2id $ me s) <$> readTVar accounts
1650 >>= mapM_ (setEstablished $ them s)
1651 announce s $ Tcp.Connection (return False) xmppSrc xmppSnk
1652 where
1653 toxSrc :: ConduitT () (Int, CryptoMessage) IO ()
1654 toxSnk :: ConduitT (Maybe Int, CryptoMessage) Void IO ()
1655 xmppSrc :: ConduitT () XML.Event IO ()
1656 xmppSnk :: ConduitT (Flush XML.Event) Void IO ()
1657
1658 toxSrc = ioToSource (atomically $ orElse (awaitAny c)
1659 $ aggregateStatus c >>= \case
1660 Dormant -> return Nothing
1661 _ -> retry)
1662 (return ())
1663 toxSnk = C.mapM_ (uncurry $ dispatchMessage c)
1664 xmppSrc = toxSrc .| C.map snd .| toxToXmpp addrTox (me s) (xmppHostname $ them s)
1665 xmppSnk = flushPassThrough xmppToTox
1666 .| C.mapMaybe (\case Flush -> Nothing
1667 Chunk x -> Just (Nothing,x))
1668 .| toxSnk
1669
1670 uniqkey <- xor24 <$> hash24 (them netcrypto) <*> hash24 (me netcrypto)
1671
1672 c <- atomically $ do
1673 mc <- Map.lookup uniqkey <$> readTVar ssvar
1674 case mc of
1675 Nothing -> do
1676 announce <- do
1677 v <- newTVar Nothing
1678 let ck = uniqueAsKey uniqkey
1679 condta s = ConnectionData (Left (Local addrTox))
1680 XMPPServer.Tox
1681 (xmppHostname $ me s)
1682 v
1683 return $ \s e -> writeTChan (xmppEventChannel sv) ( (ck, condta s), e)
1684 c <- newAggregateSession $ onStatusChange announce
1685 modifyTVar' ssvar $ Map.insert uniqkey c
1686 return c
1687 Just c -> return c
1688
1689 addSession c netcrypto
1690
1691 return ()
1625 1692
1626main :: IO () 1693main :: IO ()
1627main = do 1694main = do
@@ -1775,7 +1842,7 @@ main = do
1775 , qshowTok = (const Nothing) 1842 , qshowTok = (const Nothing)
1776 }) 1843 })
1777 , ("toxid", DHTQuery 1844 , ("toxid", DHTQuery
1778 { qsearch = toxQSearch tox 1845 { qsearch = Tox.toxQSearch tox
1779 , qhandler = -- qhandler :: ni -> nid -> IO ([ni], [r], tok) 1846 , qhandler = -- qhandler :: ni -> nid -> IO ([ni], [r], tok)
1780 (\ni nid -> 1847 (\ni nid ->
1781 Tox.unwrapAnnounceResponse Nothing 1848 Tox.unwrapAnnounceResponse Nothing
@@ -1932,6 +1999,7 @@ main = do
1932 1999
1933 _ <- UPNP.requestPorts "dht-client" $ map (Datagram,) $ baddrs ++ taddrs 2000 _ <- UPNP.requestPorts "dht-client" $ map (Datagram,) $ baddrs ++ taddrs
1934 2001
2002 ssvar <- atomically $ newTVar Map.empty
1935 (msv,mconns,mstate) <- case portxmpp opts of 2003 (msv,mconns,mstate) <- case portxmpp opts of
1936 "" -> return (Nothing,Nothing,Nothing) 2004 "" -> return (Nothing,Nothing,Nothing)
1937 p -> do 2005 p -> do
@@ -1952,7 +2020,8 @@ main = do
1952 , lookupBkts "tox6" toxdhts 2020 , lookupBkts "tox6" toxdhts
1953 ] 2021 ]
1954 2022
1955 state <- newPresenceState cw (toxman announcer toxbkts <$> mbtox) serverVar 2023 let tman = toxman ssvar announcer toxbkts <$> mbtox
2024 state <- newPresenceState cw tman serverVar
1956 2025
1957 sv <- xmppServer Tcp.noCleanUp (presenceHooks state (verbosity opts) (Just cport) (Just sport)) 2026 sv <- xmppServer Tcp.noCleanUp (presenceHooks state (verbosity opts) (Just cport) (Just sport))
1958 -- We now have a server object but it's not ready to use until 2027 -- We now have a server object but it's not ready to use until
@@ -1965,6 +2034,7 @@ main = do
1965 2034
1966 forM_ (take 1 taddrs) $ \addrTox -> do 2035 forM_ (take 1 taddrs) $ \addrTox -> do
1967 atomically $ Tox.addNewSessionHook netCryptoSessionsState $ \mbNoSpam netcrypto -> do 2036 atomically $ Tox.addNewSessionHook netCryptoSessionsState $ \mbNoSpam netcrypto -> do
2037 {-
1968 -- allsessionsMap <- atomically $ readTVar (netCryptoSessions netCryptoSessionsState) 2038 -- allsessionsMap <- atomically $ readTVar (netCryptoSessions netCryptoSessionsState)
1969 let sockAddr = Tox.ncSockAddr netcrypto 2039 let sockAddr = Tox.ncSockAddr netcrypto
1970 pubKey = Tox.ncTheirPublicKey netcrypto 2040 pubKey = Tox.ncTheirPublicKey netcrypto
@@ -1975,15 +2045,21 @@ main = do
1975 onEOF = return () -- setTerminate is called elsewhere. 2045 onEOF = return () -- setTerminate is called elsewhere.
1976 xmppSrc = ioToSource receiveCrypto onEOF 2046 xmppSrc = ioToSource receiveCrypto onEOF
1977 xmppSink = newXmmpSink netcrypto 2047 xmppSink = newXmmpSink netcrypto
2048 -}
1978 forM_ msv $ \sv -> do 2049 forM_ msv $ \sv -> do
1979 let Tox.HaveDHTKey saddr = Tox.ncSockAddr netcrypto 2050 let Tox.HaveDHTKey saddr = Tox.ncSockAddr netcrypto
2051 {-
1980 Tox.HaveDHTKey dkey = Tox.ncTheirDHTKey netcrypto 2052 Tox.HaveDHTKey dkey = Tox.ncTheirDHTKey netcrypto
1981 nid = Tox.key2id dkey 2053 nid = Tox.key2id dkey
1982 them = Tox.ncTheirPublicKey netcrypto 2054 them = Tox.ncTheirPublicKey netcrypto
1983 me = Tox.ncMyPublicKey netcrypto 2055 me = Tox.ncMyPublicKey netcrypto
2056
1984 announceToxJabberPeer me them (xmppEventChannel sv) addrTox saddr pingflag xmppSrc xmppSink 2057 announceToxJabberPeer me them (xmppEventChannel sv) addrTox saddr pingflag xmppSrc xmppSink
2058 -}
2059
1985 forM_ mbtox $ \tox -> do 2060 forM_ mbtox $ \tox -> do
1986 let ContactInfo{accounts} = Tox.toxContactInfo tox 2061 onNewToxSession sv ssvar (Tox.toxContactInfo tox) saddr netcrypto
2062 {-
1987 mbacc <- HashMap.lookup (Tox.key2id me) 2063 mbacc <- HashMap.lookup (Tox.key2id me)
1988 <$> atomically (readTVar accounts) 2064 <$> atomically (readTVar accounts)
1989 -- TODO: Add account if it doesn't exist? 2065 -- TODO: Add account if it doesn't exist?
@@ -1998,6 +2074,7 @@ main = do
1998 let (listenerId,supply') = freshId supply 2074 let (listenerId,supply') = freshId supply
1999 writeTVar (Tox.listenerIDSupply netCryptoSessionsState) supply' 2075 writeTVar (Tox.listenerIDSupply netCryptoSessionsState) supply'
2000 modifyTVar' (Tox.ncListeners netcrypto) (IntMap.insert listenerId (0,tmchan)) 2076 modifyTVar' (Tox.ncListeners netcrypto) (IntMap.insert listenerId (0,tmchan))
2077 -}
2001 return Nothing 2078 return Nothing
2002 2079
2003 let dhts = Map.union btdhts toxdhts 2080 let dhts = Map.union btdhts toxdhts
diff --git a/src/Network/Tox.hs b/src/Network/Tox.hs
index c1cdb151..3ad2b11e 100644
--- a/src/Network/Tox.hs
+++ b/src/Network/Tox.hs
@@ -32,6 +32,7 @@ import qualified Data.ByteString as B
32import qualified Data.ByteString.Char8 as C8 32import qualified Data.ByteString.Char8 as C8
33import Data.Data 33import Data.Data
34import Data.Functor.Contravariant 34import Data.Functor.Contravariant
35import Data.IP
35import Data.Maybe 36import Data.Maybe
36import qualified Data.MinMaxPSQ as MinMaxPSQ 37import qualified Data.MinMaxPSQ as MinMaxPSQ
37import qualified Data.Serialize as S 38import qualified Data.Serialize as S
@@ -50,7 +51,9 @@ import Connection
50import Crypto.Tox 51import Crypto.Tox
51import Data.Word64Map (fitsInInt) 52import Data.Word64Map (fitsInInt)
52import qualified Data.Word64Map (empty) 53import qualified Data.Word64Map (empty)
54import HandshakeCache
53import Network.Kademlia.Bootstrap (forkPollForRefresh, bootstrap) 55import Network.Kademlia.Bootstrap (forkPollForRefresh, bootstrap)
56import Network.Kademlia.Search
54import Network.Tox.Crypto.Transport (Handshake(..),CryptoPacket) 57import Network.Tox.Crypto.Transport (Handshake(..),CryptoPacket)
55import Network.Tox.Handshake 58import Network.Tox.Handshake
56import Network.Tox.Crypto.Handlers 59import Network.Tox.Crypto.Handlers
@@ -203,6 +206,7 @@ data Tox extra = Tox
203 , toxToRoute :: Transport String Onion.AnnouncedRendezvous (PublicKey,Onion.OnionData) 206 , toxToRoute :: Transport String Onion.AnnouncedRendezvous (PublicKey,Onion.OnionData)
204 , toxCrypto :: Transport String SockAddr (CryptoPacket Encrypted) 207 , toxCrypto :: Transport String SockAddr (CryptoPacket Encrypted)
205 , toxHandshakes :: Transport String SockAddr (Handshake Encrypted) 208 , toxHandshakes :: Transport String SockAddr (Handshake Encrypted)
209 , toxHandshakeCache :: HandshakeCache
206 , toxCryptoSessions :: NetCryptoSessions 210 , toxCryptoSessions :: NetCryptoSessions
207 , toxCryptoKeys :: TransportCrypto 211 , toxCryptoKeys :: TransportCrypto
208 , toxRouting :: DHT.Routing 212 , toxRouting :: DHT.Routing
@@ -442,6 +446,8 @@ newToxOverTransport keydb addr mbSessionsState suppliedDHTKey udp = do
442 dhtclient <- newClient drg dhtnet0 DHT.classify (myAddr tbl4 tbl6) (DHT.handlers crypto . mkrouting) id 446 dhtclient <- newClient drg dhtnet0 DHT.classify (myAddr tbl4 tbl6) (DHT.handlers crypto . mkrouting) id
443 $ \client net -> onInbound (DHT.updateRouting client (mkrouting client) orouter) net 447 $ \client net -> onInbound (DHT.updateRouting client (mkrouting client) orouter) net
444 448
449 hscache <- newHandshakeCache crypto (sendMessage handshakes)
450
445 let sessionsState = sessionsState0 { sendHandshake = sendMessage handshakes 451 let sessionsState = sessionsState0 { sendHandshake = sendMessage handshakes
446 , sendSessionPacket = sendMessage cryptonet 452 , sendSessionPacket = sendMessage cryptonet
447 , transportCrypto = crypto 453 , transportCrypto = crypto
@@ -479,6 +485,7 @@ newToxOverTransport keydb addr mbSessionsState suppliedDHTKey udp = do
479 , toxToRoute = onInbound (updateContactInfo roster) dtacrypt 485 , toxToRoute = onInbound (updateContactInfo roster) dtacrypt
480 , toxCrypto = addHandler (dput XMisc) (sessionPacketH sessionsState) cryptonet 486 , toxCrypto = addHandler (dput XMisc) (sessionPacketH sessionsState) cryptonet
481 , toxHandshakes = addHandler (dput XMisc) (handshakeH sessionsState) handshakes 487 , toxHandshakes = addHandler (dput XMisc) (handshakeH sessionsState) handshakes
488 , toxHandshakeCache = hscache
482 , toxCryptoSessions = sessionsState 489 , toxCryptoSessions = sessionsState
483 , toxCryptoKeys = crypto 490 , toxCryptoKeys = crypto
484 , toxRouting = mkrouting dhtclient 491 , toxRouting = mkrouting dhtclient
@@ -550,3 +557,7 @@ announceToLan sock nid = do
550 let broadcast = addrAddress broadcast_info 557 let broadcast = addrAddress broadcast_info
551 bs = S.runPut $ DHT.putMessage (DHT.DHTLanDiscovery nid) 558 bs = S.runPut $ DHT.putMessage (DHT.DHTLanDiscovery nid)
552 saferSendTo sock bs broadcast 559 saferSendTo sock bs broadcast
560
561toxQSearch :: Tox extra -> Search NodeId (IP, PortNumber) Nonce32 NodeInfo Onion.Rendezvous
562toxQSearch tox = Onion.toxidSearch (onionTimeout tox) (toxCryptoKeys tox) (toxOnion tox)
563