diff options
author | joe <joe@jerkface.net> | 2018-06-18 06:14:11 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2018-06-18 06:14:11 -0400 |
commit | 19364a287f7083fc60beed2d6eae3dd71d27e737 (patch) | |
tree | bb784eeb3c8acb25fd8b656142d92aac2dd096ca | |
parent | 2dbb1e710d6d58fc00126d84763ec3597d92437d (diff) |
tox: Automatically share dhtkey with roster contacts.
-rw-r--r-- | ToxManager.hs | 12 | ||||
-rw-r--r-- | ToxToXMPP.hs | 104 | ||||
-rw-r--r-- | examples/dhtd.hs | 8 | ||||
-rw-r--r-- | src/Network/Tox.hs | 1 | ||||
-rw-r--r-- | src/Network/Tox/ContactInfo.hs | 9 |
5 files changed, 112 insertions, 22 deletions
diff --git a/ToxManager.hs b/ToxManager.hs index aa838027..af1911d4 100644 --- a/ToxManager.hs +++ b/ToxManager.hs | |||
@@ -38,9 +38,6 @@ import Control.Concurrent.Lifted | |||
38 | import GHC.Conc (labelThread) | 38 | import GHC.Conc (labelThread) |
39 | #endif | 39 | #endif |
40 | 40 | ||
41 | toxAnnounceInterval :: POSIXTime | ||
42 | toxAnnounceInterval = 15 | ||
43 | |||
44 | toxAnnounceSendData :: Tox.Tox -> PublicKey | 41 | toxAnnounceSendData :: Tox.Tox -> PublicKey |
45 | -> Nonce32 | 42 | -> Nonce32 |
46 | -> Maybe Tox.NodeInfo | 43 | -> Maybe Tox.NodeInfo |
@@ -55,13 +52,6 @@ toxAnnounceSendData tox pubkey token = \case | |||
55 | Nothing -> return Nothing | 52 | Nothing -> return Nothing |
56 | 53 | ||
57 | 54 | ||
58 | toxQSearch :: Tox.Tox -> Search Tox.NodeId (IP, PortNumber) Nonce32 Tox.NodeInfo Tox.Rendezvous | ||
59 | toxQSearch tox = Tox.toxidSearch (Tox.onionTimeout tox) (Tox.toxCryptoKeys tox) (Tox.toxOnion tox) | ||
60 | |||
61 | interweave :: [a] -> [a] -> [a] | ||
62 | interweave [] ys = ys | ||
63 | interweave (x:xs) ys = x : interweave ys xs | ||
64 | |||
65 | -- | | 55 | -- | |
66 | -- | 56 | -- |
67 | -- These hooks will be invoked in order to connect to *.tox hosts in a user's | 57 | -- These hooks will be invoked in order to connect to *.tox hosts in a user's |
@@ -100,7 +90,7 @@ toxman announcer toxbkts tox presence = ToxManager | |||
100 | toxAnnounceInterval) | 90 | toxAnnounceInterval) |
101 | pub | 91 | pub |
102 | 92 | ||
103 | forkAccountWatcher acnt tox presence | 93 | forkAccountWatcher acnt tox presence announcer |
104 | return () | 94 | return () |
105 | 95 | ||
106 | , deactivateAccount = \k pubname -> do | 96 | , deactivateAccount = \k pubname -> do |
diff --git a/ToxToXMPP.hs b/ToxToXMPP.hs index edbf35ca..ac24ce6d 100644 --- a/ToxToXMPP.hs +++ b/ToxToXMPP.hs | |||
@@ -1,5 +1,6 @@ | |||
1 | {-# LANGUAGE CPP #-} | 1 | {-# LANGUAGE CPP #-} |
2 | {-# LANGUAGE LambdaCase #-} | 2 | {-# LANGUAGE LambdaCase #-} |
3 | {-# LANGUAGE NamedFieldPuns #-} | ||
3 | module ToxToXMPP where | 4 | module ToxToXMPP where |
4 | 5 | ||
5 | import Data.Conduit as C | 6 | import Data.Conduit as C |
@@ -9,23 +10,52 @@ import Network.Tox.Crypto.Transport as Tox | |||
9 | import XMPPServer as XMPP | 10 | import XMPPServer as XMPP |
10 | import EventUtil | 11 | import EventUtil |
11 | 12 | ||
13 | import Announcer | ||
14 | import Announcer.Tox | ||
15 | import Connection | ||
16 | import Network.QueryResponse | ||
17 | -- import Control.Concurrent | ||
18 | import Control.Concurrent.STM | ||
19 | import Control.Monad | ||
20 | import Crypto.Tox | ||
21 | import qualified Data.HashMap.Strict as HashMap | ||
22 | import Data.Maybe | ||
23 | import qualified Data.Set as Set | ||
24 | import qualified Data.Text as T | ||
25 | import Data.Time.Clock.POSIX | ||
26 | import Network.Address | ||
27 | import Network.Kademlia.Search | ||
28 | import qualified Network.Tox as Tox | ||
29 | import Network.Tox.ContactInfo as Tox | ||
30 | import qualified Network.Tox.Crypto.Handlers as Tox | ||
31 | -- import qualified Network.Tox.DHT.Handlers as Tox | ||
32 | import Announcer | ||
12 | import ClientState | 33 | import ClientState |
13 | import Control.Concurrent.STM | 34 | import Control.Concurrent.STM |
14 | import Control.Monad | 35 | import Control.Monad |
15 | import Crypto.Tox | 36 | import Crypto.Tox |
16 | import Data.Bits | 37 | import Data.Bits |
17 | import Data.Function | 38 | import Data.Function |
18 | import qualified Data.Map as Map | 39 | import qualified Data.Map as Map |
19 | import qualified Data.Set as Set | 40 | import qualified Data.Set as Set |
20 | import qualified Data.Text as T | 41 | import qualified Data.Text as T |
21 | ;import Data.Text (Text) | 42 | ;import Data.Text (Text) |
22 | import Data.Word | 43 | import Data.Word |
44 | import qualified Network.Kademlia.Routing as R | ||
23 | import Network.Tox | 45 | import Network.Tox |
24 | import Network.Tox.ContactInfo | 46 | import Network.Tox.ContactInfo |
25 | import Network.Tox.DHT.Transport (FriendRequest (..)) | 47 | import Network.Tox.DHT.Handlers |
48 | import qualified Network.Tox.DHT.Transport as Tox | ||
49 | ;import Network.Tox.DHT.Transport (FriendRequest (..)) | ||
26 | import Network.Tox.NodeId | 50 | import Network.Tox.NodeId |
27 | import Network.Tox.Onion.Transport (OnionData (..)) | 51 | import qualified Network.Tox.Onion.Handlers as Tox |
52 | import qualified Network.Tox.Onion.Transport as Tox | ||
53 | ;import Network.Tox.Onion.Transport (OnionData (..)) | ||
54 | import Presence | ||
28 | import Presence | 55 | import Presence |
56 | import System.IO | ||
57 | import Text.Read | ||
58 | import XMPPServer (ConnectionKey) | ||
29 | #ifdef THREAD_DEBUG | 59 | #ifdef THREAD_DEBUG |
30 | import Control.Concurrent.Lifted.Instrument | 60 | import Control.Concurrent.Lifted.Instrument |
31 | #else | 61 | #else |
@@ -93,8 +123,13 @@ dispatch acnt st (OnionRouted theirkey (OnionFriendRequest fr) ) = do | |||
93 | -- embed it in the stanza as a <status> element. | 123 | -- embed it in the stanza as a <status> element. |
94 | sendModifiedStanzaToClient ask (connChan conn) | 124 | sendModifiedStanzaToClient ask (connChan conn) |
95 | 125 | ||
96 | forkAccountWatcher :: Account -> Tox -> PresenceState -> IO ThreadId | 126 | interweave :: [a] -> [a] -> [a] |
97 | forkAccountWatcher acc tox st = forkIO $ do | 127 | interweave [] ys = ys |
128 | interweave (x:xs) ys = x : interweave ys xs | ||
129 | |||
130 | |||
131 | forkAccountWatcher :: Account -> Tox -> PresenceState -> Announcer -> IO ThreadId | ||
132 | forkAccountWatcher acc tox st announcer = forkIO $ do | ||
98 | myThreadId >>= flip labelThread ("tox-xmpp:" | 133 | myThreadId >>= flip labelThread ("tox-xmpp:" |
99 | ++ show (key2id $ toPublic $ userSecret acc)) | 134 | ++ show (key2id $ toPublic $ userSecret acc)) |
100 | (chan,contacts) <- atomically $ do | 135 | (chan,contacts) <- atomically $ do |
@@ -103,6 +138,49 @@ forkAccountWatcher acc tox st = forkIO $ do | |||
103 | return (chan,contacts) | 138 | return (chan,contacts) |
104 | -- TODO: process information in contacts HashMap. | 139 | -- TODO: process information in contacts HashMap. |
105 | 140 | ||
141 | let nearNodes nid = do | ||
142 | bkts4 <- readTVar $ routing4 $ toxRouting tox | ||
143 | bkts6 <- readTVar $ routing6 $ toxRouting tox | ||
144 | let nss = map (R.kclosest (searchSpace (toxQSearch tox)) searchK nid) | ||
145 | [bkts4,bkts6] | ||
146 | return $ foldr interweave [] nss | ||
147 | |||
148 | |||
149 | forM_ (HashMap.toList contacts) $ \(them,Contact{contactPolicy}) -> do | ||
150 | wanted <- atomically $ (==Just TryingToConnect) <$> readTVar contactPolicy | ||
151 | when wanted $ do | ||
152 | let pub = toPublic $ userSecret acc | ||
153 | akey <- atomically $ packAnnounceKey announcer $ "dhtkey:" ++ show them | ||
154 | -- We send this packet every 30 seconds if there is more | ||
155 | -- than one peer (in the 8) that says they our friend is | ||
156 | -- announced on them. This packet can also be sent through | ||
157 | -- the DHT module as a DHT request packet (see DHT) if we | ||
158 | -- know the DHT public key of the friend and are looking | ||
159 | -- for them in the DHT but have not connected to them yet. | ||
160 | -- 30 second is a reasonable timeout to not flood the | ||
161 | -- network with too many packets while making sure the | ||
162 | -- other will eventually receive the packet. Since packets | ||
163 | -- are sent through every peer that knows the friend, | ||
164 | -- resending it right away without waiting has a high | ||
165 | -- likelihood of failure as the chances of packet loss | ||
166 | -- happening to all (up to to 8) packets sent is low. | ||
167 | -- | ||
168 | schedule announcer | ||
169 | akey | ||
170 | (AnnounceMethod (toxQSearch tox) | ||
171 | (Left $ \theirkey rendezvous -> do | ||
172 | dkey <- Tox.getContactInfo tox | ||
173 | sendMessage | ||
174 | (Tox.toxToRoute tox) | ||
175 | (Tox.AnnouncedRendezvous theirkey rendezvous) | ||
176 | (pub,Tox.OnionDHTPublicKey dkey)) | ||
177 | nearNodes | ||
178 | them | ||
179 | 30) -- every 30 seconds | ||
180 | pub | ||
181 | |||
182 | |||
183 | |||
106 | -- Loop endlessly until clientRefs is null. | 184 | -- Loop endlessly until clientRefs is null. |
107 | fix $ \loop -> do | 185 | fix $ \loop -> do |
108 | mev <- atomically $ | 186 | mev <- atomically $ |
@@ -113,3 +191,9 @@ forkAccountWatcher acc tox st = forkIO $ do | |||
113 | return Nothing | 191 | return Nothing |
114 | forM_ mev $ \ev -> dispatch acc st ev >> loop | 192 | forM_ mev $ \ev -> dispatch acc st ev >> loop |
115 | 193 | ||
194 | toxQSearch :: Tox.Tox -> Search Tox.NodeId (IP, PortNumber) Nonce32 Tox.NodeInfo Tox.Rendezvous | ||
195 | toxQSearch tox = Tox.toxidSearch (Tox.onionTimeout tox) (Tox.toxCryptoKeys tox) (Tox.toxOnion tox) | ||
196 | |||
197 | toxAnnounceInterval :: POSIXTime | ||
198 | toxAnnounceInterval = 15 | ||
199 | |||
diff --git a/examples/dhtd.hs b/examples/dhtd.hs index d7a069b4..28bfc9b4 100644 --- a/examples/dhtd.hs +++ b/examples/dhtd.hs | |||
@@ -1718,7 +1718,13 @@ main = runResourceT $ liftBaseWith $ \resT -> do | |||
1718 | forM_ msv $ \sv -> do | 1718 | forM_ msv $ \sv -> do |
1719 | let Tox.HaveDHTKey saddr = Tox.ncSockAddr netcrypto | 1719 | let Tox.HaveDHTKey saddr = Tox.ncSockAddr netcrypto |
1720 | announceToxJabberPeer (Tox.ncTheirPublicKey netcrypto) (xmppEventChannel sv) addrTox saddr pingflag xmppSrc xmppSink | 1720 | announceToxJabberPeer (Tox.ncTheirPublicKey netcrypto) (xmppEventChannel sv) addrTox saddr pingflag xmppSrc xmppSink |
1721 | -- TODO: Update toxContactInfo, connected. | 1721 | forM_ mbtox $ \tox -> do |
1722 | let ContactInfo{accounts} = Tox.toxContactInfo tox | ||
1723 | mbacc <- HashMap.lookup (Tox.key2id $ Tox.ncMyPublicKey netcrypto) | ||
1724 | <$> atomically (readTVar accounts) | ||
1725 | forM_ mbacc $ \acnt -> do | ||
1726 | now <- getPOSIXTime | ||
1727 | atomically $ setEstablished now (Tox.ncTheirPublicKey netcrypto) acnt | ||
1722 | atomically $ do | 1728 | atomically $ do |
1723 | supply <- readTVar (Tox.listenerIDSupply netCryptoSessionsState) | 1729 | supply <- readTVar (Tox.listenerIDSupply netCryptoSessionsState) |
1724 | let (listenerId,supply') = freshId supply | 1730 | let (listenerId,supply') = freshId supply |
diff --git a/src/Network/Tox.hs b/src/Network/Tox.hs index 5a4c02ea..52dba0f5 100644 --- a/src/Network/Tox.hs +++ b/src/Network/Tox.hs | |||
@@ -351,6 +351,7 @@ netCryptoWithBackoff millisecs tox myseckey theirpubkey = do | |||
351 | hPutStrLn stderr "Unable to establish session..." | 351 | hPutStrLn stderr "Unable to establish session..." |
352 | return [] | 352 | return [] |
353 | 353 | ||
354 | -- | Create a DHTPublicKey packet to send to a remote contact. | ||
354 | getContactInfo :: Tox -> IO DHT.DHTPublicKey | 355 | getContactInfo :: Tox -> IO DHT.DHTPublicKey |
355 | getContactInfo Tox{toxCryptoKeys,toxRouting} = join $ atomically $ do | 356 | getContactInfo Tox{toxCryptoKeys,toxRouting} = join $ atomically $ do |
356 | r4 <- readTVar $ DHT.routing4 toxRouting | 357 | r4 <- readTVar $ DHT.routing4 toxRouting |
diff --git a/src/Network/Tox/ContactInfo.hs b/src/Network/Tox/ContactInfo.hs index 47c07237..9f29d587 100644 --- a/src/Network/Tox/ContactInfo.hs +++ b/src/Network/Tox/ContactInfo.hs | |||
@@ -34,6 +34,8 @@ data Account = Account | |||
34 | data ContactEvent = OnionRouted { contact :: PublicKey, onionRouted :: OnionData } | 34 | data ContactEvent = OnionRouted { contact :: PublicKey, onionRouted :: OnionData } |
35 | | PolicyChange { contact :: PublicKey, policyChange :: Policy } | 35 | | PolicyChange { contact :: PublicKey, policyChange :: Policy } |
36 | | AddrChange { contact :: PublicKey, addrChange :: SockAddr } | 36 | | AddrChange { contact :: PublicKey, addrChange :: SockAddr } |
37 | | SessionEstablished { contact :: PublicKey } | ||
38 | | SessionTerminated { contact :: PublicKey } | ||
37 | 39 | ||
38 | data Contact = Contact | 40 | data Contact = Contact |
39 | { contactKeyPacket :: TVar (Maybe (POSIXTime,DHT.DHTPublicKey)) | 41 | { contactKeyPacket :: TVar (Maybe (POSIXTime,DHT.DHTPublicKey)) |
@@ -105,6 +107,13 @@ setContactAddr now remoteUserKey addr acc = do | |||
105 | updateAccount' remoteUserKey acc $ addrUpdate now addr | 107 | updateAccount' remoteUserKey acc $ addrUpdate now addr |
106 | writeTChan (eventChan acc) $ AddrChange remoteUserKey addr | 108 | writeTChan (eventChan acc) $ AddrChange remoteUserKey addr |
107 | 109 | ||
110 | setEstablished :: POSIXTime -> PublicKey -> Account -> STM () | ||
111 | setEstablished now remoteUserKey acc = | ||
112 | writeTChan (eventChan acc) $ SessionEstablished remoteUserKey | ||
113 | |||
114 | setTerminated :: POSIXTime -> PublicKey -> Account -> STM () | ||
115 | setTerminated now remoteUserKey acc = | ||
116 | writeTChan (eventChan acc) $ SessionTerminated remoteUserKey | ||
108 | 117 | ||
109 | 118 | ||
110 | addContactInfo :: ContactInfo -> SecretKey -> STM () | 119 | addContactInfo :: ContactInfo -> SecretKey -> STM () |