summaryrefslogtreecommitdiff
path: root/src/Network/Tox.hs
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2018-09-08 06:37:10 -0400
committerJoe Crayne <joe@jerkface.net>2018-11-03 10:23:45 -0400
commit36cd21f0b42c09cbcf3a215afbcd754cc37d1c4e (patch)
tree548a3c6eb5c03692327f561a6d5afbcf3c1d5f4e /src/Network/Tox.hs
parent0c7768ba8eb62a6a74176f737a1c9c42308d5a8c (diff)
Switched to new session tracker.
Diffstat (limited to 'src/Network/Tox.hs')
-rw-r--r--src/Network/Tox.hs165
1 files changed, 27 insertions, 138 deletions
diff --git a/src/Network/Tox.hs b/src/Network/Tox.hs
index 861d71d3..88228c50 100644
--- a/src/Network/Tox.hs
+++ b/src/Network/Tox.hs
@@ -32,31 +32,25 @@ 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
36import Data.Maybe 35import Data.Maybe
37import qualified Data.MinMaxPSQ as MinMaxPSQ 36import qualified Data.MinMaxPSQ as MinMaxPSQ
38import qualified Data.Serialize as S 37import qualified Data.Serialize as S
39import Data.Time.Clock.POSIX (getPOSIXTime) 38import Data.Time.Clock.POSIX (getPOSIXTime)
40import Data.Word 39import Data.Word
40import Network.Socket
41import System.Endian
42
43import Network.BitTorrent.DHT.Token as Token
41import qualified Data.Wrapper.PSQ as PSQ 44import qualified Data.Wrapper.PSQ as PSQ
42import System.Global6 45import System.Global6
43import Network.Address (WantIP (..)) 46import Network.Address (WantIP (..),IP)
44import qualified Network.Kademlia.Routing as R 47import qualified Network.Kademlia.Routing as R
45import Network.QueryResponse 48import Network.QueryResponse
46import Network.Socket
47import System.Endian
48import Network.BitTorrent.DHT.Token as Token
49
50import Connection
51import Crypto.Tox 49import Crypto.Tox
52import Data.Word64Map (fitsInInt) 50import Data.Word64Map (fitsInInt)
53import qualified Data.Word64Map (empty) 51import qualified Data.Word64Map (empty)
54import HandshakeCache
55import Network.Kademlia.Bootstrap (forkPollForRefresh, bootstrap) 52import Network.Kademlia.Bootstrap (forkPollForRefresh, bootstrap)
56import Network.Kademlia.Search
57import Network.Tox.Crypto.Transport (Handshake(..),CryptoPacket) 53import Network.Tox.Crypto.Transport (Handshake(..),CryptoPacket)
58import Network.Tox.Handshake
59import Network.Tox.Crypto.Handlers
60import qualified Network.Tox.DHT.Handlers as DHT 54import qualified Network.Tox.DHT.Handlers as DHT
61import qualified Network.Tox.DHT.Transport as DHT 55import qualified Network.Tox.DHT.Transport as DHT
62import Network.Tox.NodeId 56import Network.Tox.NodeId
@@ -66,12 +60,12 @@ import Network.Tox.Transport
66import OnionRouter 60import OnionRouter
67import Network.Tox.ContactInfo 61import Network.Tox.ContactInfo
68import Text.XXD 62import Text.XXD
69import qualified Data.HashMap.Strict as HashMap
70import qualified Data.Map.Strict as Map
71import DPut 63import DPut
72import Network.Tox.Avahi 64import Network.Tox.Avahi
73import Text.Printf 65import Network.Tox.Session
74import Data.List 66import Network.SessionTransports
67import Network.Kademlia.Search
68import HandshakeCache
75 69
76newCrypto :: IO TransportCrypto 70newCrypto :: IO TransportCrypto
77newCrypto = do 71newCrypto = do
@@ -207,7 +201,6 @@ data Tox extra = Tox
207 , toxCrypto :: Transport String SockAddr (CryptoPacket Encrypted) 201 , toxCrypto :: Transport String SockAddr (CryptoPacket Encrypted)
208 , toxHandshakes :: Transport String SockAddr (Handshake Encrypted) 202 , toxHandshakes :: Transport String SockAddr (Handshake Encrypted)
209 , toxHandshakeCache :: HandshakeCache 203 , toxHandshakeCache :: HandshakeCache
210 , toxCryptoSessions :: NetCryptoSessions
211 , toxCryptoKeys :: TransportCrypto 204 , toxCryptoKeys :: TransportCrypto
212 , toxRouting :: DHT.Routing 205 , toxRouting :: DHT.Routing
213 , toxTokens :: TVar SessionTokens 206 , toxTokens :: TVar SessionTokens
@@ -217,97 +210,7 @@ data Tox extra = Tox
217 , toxAnnounceToLan :: IO () 210 , toxAnnounceToLan :: IO ()
218 } 211 }
219 212
220-- | initiate a netcrypto session, blocking 213
221netCrypto :: Tox extra -> SecretKey -> PublicKey{-UserKey -} -> IO [NetCryptoSession]
222netCrypto tox myseckey theirpubkey = netCryptoWithBackoff 1000000 tox myseckey theirpubkey
223
224-- | helper for 'netCrypto', initiate a netcrypto session, retry after specified millisecs
225netCryptoWithBackoff :: Int -> Tox extra -> SecretKey -> PublicKey -> IO [NetCryptoSession]
226netCryptoWithBackoff millisecs tox myseckey theirpubkey = do
227 let mykeyAsId = key2id (toPublic myseckey)
228 -- TODO: check status of connection here:
229 mbContactsVar <- fmap contacts . HashMap.lookup mykeyAsId <$> atomically (readTVar (accounts (toxContactInfo tox)))
230 case mbContactsVar of
231 Nothing -> do
232 dput XNetCrypto ("netCrypto: (" ++ show mykeyAsId ++") accounts lookup failed.")
233 return []
234
235 Just contactsVar -> do
236 let theirkeyAsId = key2id theirpubkey
237 mbContact <- HashMap.lookup theirkeyAsId <$> atomically (readTVar contactsVar)
238 tup <- atomically $ do
239 mc <- HashMap.lookup theirkeyAsId <$> readTVar contactsVar
240 kp <- fmap join $ forM mc $ \c -> readTVar (contactKeyPacket c)
241 sa <- fmap join $ forM mc $ \c -> readTVar (contactLastSeenAddr c)
242 fr <- fmap join $ forM mc $ \c -> readTVar (contactFriendRequest c)
243 cp <- fmap join $ forM mc $ \c -> readTVar (contactPolicy c)
244 return (kp,sa,fr,cp)
245 case tup of
246 (Nothing,Nothing,Nothing,Nothing) -> do
247 dput XNetCrypto ("netCrypto: (" ++ show mykeyAsId ++") friend not found (" ++ show theirkeyAsId ++ ").")
248 return []
249 (mbKeyPkt,Nothing,mbFR,mbPolicy) -> do
250 dput XNetCrypto ("netCrypto: (" ++ show mykeyAsId ++") no SockAddr for friend (" ++ show theirkeyAsId ++ "). TODO: search their node?")
251 return []
252 (Nothing,_,_,_) -> do
253 dput XNetCrypto ("netCrypto: (" ++ show mykeyAsId ++") no DHT-key for friend (" ++ show theirkeyAsId ++ "). TODO: what?")
254 return []
255 (Just (stamp_theirDhtKey,keyPkt),Just (stamp_saddr,saddr),mbFR,mbPolicy)
256 | theirDhtKey <- DHT.dhtpk keyPkt -> do
257 -- Do we already have an active session with this user?
258 sessionsMap <- atomically $ readTVar (netCryptoSessionsByKey (toxCryptoSessions tox) )
259 let sessionUsesIdentity key session = key == ncMyPublicKey session
260 case Map.lookup theirpubkey sessionsMap of
261 -- if sessions found, is it using this private key?
262 Just sessions | matchedSessions <- filter (sessionUsesIdentity (toPublic myseckey)) sessions
263 , not (null matchedSessions)
264 -> do
265 dput XNetCrypto ("netCrypto: Already have a session for " ++ show mykeyAsId ++ "<-->" ++ show theirkeyAsId)
266 return matchedSessions
267 -- if not, send handshake, this is separate session
268 _ -> do
269 -- if no session:
270 -- Convert to NodeInfo, so we can send cookieRequest
271 let crypto = toxCryptoKeys tox
272 client = toxDHT tox
273 case nodeInfo (key2id theirDhtKey) (nodeAddr saddr) of
274 Left e -> dput XNetCrypto ("netCrypto: nodeInfo fail... " ++ e) >> return []
275 Right ni -> do
276 mbCookie <- DHT.cookieRequest crypto client (toPublic myseckey) ni
277 case mbCookie of
278 Nothing -> do
279 dput XNetCrypto ("netCrypto: (" ++ show mykeyAsId ++") <--> (" ++ show theirkeyAsId ++ ").")
280 dput XNetCrypto ("netCrypto: CookieRequest failed. TODO: dhtpkNodes thingy")
281 return []
282 Just cookie -> do
283 dput XNetCrypto "Have cookie, creating handshake packet..."
284 let hp = HParam { hpOtherCookie = cookie
285 , hpMySecretKey = myseckey
286 , hpCookieRemotePubkey = theirpubkey
287 , hpCookieRemoteDhtkey = theirDhtKey
288 , hpTheirBaseNonce = Nothing
289 , hpTheirSessionKeyPublic = Nothing
290 }
291 newsession <- generateSecretKey
292 timestamp <- getPOSIXTime
293 (myhandshake,ioAction)
294 <- atomically $ freshCryptoSession (toxCryptoSessions tox) (nodeAddr saddr) newsession timestamp hp
295 ioAction
296 -- send handshake
297 forM myhandshake $ \response_handshake -> do
298 sendHandshake (toxCryptoSessions tox) (nodeAddr saddr) response_handshake
299 let secnum :: Double
300 secnum = fromIntegral millisecs / 1000000
301 delay = (millisecs * 5 `div` 4)
302 if secnum < 20000000
303 then do
304 dput XNetCrypto $ "sent handshake, now delaying " ++ show (secnum * 1.25) ++ " second(s).."
305 -- threadDelay delay
306 -- Commenting loop for simpler debugging
307 return [] -- netCryptoWithBackoff delay tox myseckey theirpubkey -- hopefully it will find an active session this time.
308 else do
309 dput XNetCrypto "Unable to establish session..."
310 return []
311 214
312-- | Create a DHTPublicKey packet to send to a remote contact. 215-- | Create a DHTPublicKey packet to send to a remote contact.
313getContactInfo :: Tox extra -> IO DHT.DHTPublicKey 216getContactInfo :: Tox extra -> IO DHT.DHTPublicKey
@@ -365,30 +268,24 @@ getOnionAlias crypto dhtself remoteNode = atomically $ do
365 268
366newTox :: TVar Onion.AnnouncedKeys -- ^ Store of announced keys we are a rendezvous for. 269newTox :: TVar Onion.AnnouncedKeys -- ^ Store of announced keys we are a rendezvous for.
367 -> SockAddr -- ^ Bind-address to listen on. 270 -> SockAddr -- ^ Bind-address to listen on.
368 -> Maybe NetCryptoSessions -- ^ State of all one-on-one Tox links. 271 -> ( ContactInfo extra -> SockAddr -> Session -> IO () )
369 -> Maybe SecretKey -- ^ Optional DHT secret key to use. 272 -> Maybe SecretKey -- ^ Optional DHT secret key to use.
370 -> IO (Tox extra) 273 -> IO (Tox extra)
371newTox keydb addr mbSessionsState suppliedDHTKey = do 274newTox keydb addr onsess suppliedDHTKey = do
372 (udp,sock) <- {- addVerbosity <$> -} udpTransport' addr 275 (udp,sock) <- {- addVerbosity <$> -} udpTransport' addr
373 tox <- newToxOverTransport keydb addr mbSessionsState suppliedDHTKey udp 276 tox <- newToxOverTransport keydb addr onsess suppliedDHTKey udp
374 return tox { toxAnnounceToLan = announceToLan sock (key2id $ transportPublic $ toxCryptoKeys tox) } 277 return tox { toxAnnounceToLan = announceToLan sock (key2id $ transportPublic $ toxCryptoKeys tox) }
375 278
376-- | This version of 'newTox' is useful for automated tests using 'testPairTransport'. 279-- | This version of 'newTox' is useful for automated tests using 'testPairTransport'.
377newToxOverTransport :: TVar Onion.AnnouncedKeys 280newToxOverTransport :: TVar Onion.AnnouncedKeys
378 -> SockAddr 281 -> SockAddr
379 -> Maybe NetCryptoSessions 282 -> ( ContactInfo extra -> SockAddr -> Session -> IO () )
380 -> Maybe SecretKey 283 -> Maybe SecretKey
381 -> Onion.UDPTransport 284 -> Onion.UDPTransport
382 -> IO (Tox extra) 285 -> IO (Tox extra)
383newToxOverTransport keydb addr mbSessionsState suppliedDHTKey udp = do 286newToxOverTransport keydb addr onNewSession suppliedDHTKey udp = do
384 roster <- newContactInfo 287 roster <- newContactInfo
385 (crypto0,sessionsState0) <- case mbSessionsState of 288 crypto0 <- newCrypto
386 Nothing -> do
387 crypto <- newCrypto
388 sessionsState <- newSessionsState crypto (const $ dput XUnexpected "Missing destroy hook!") defaultUnRecHook defaultCryptoDataHooks
389 return (crypto,sessionsState)
390 Just s -> return (transportCrypto s, s)
391
392 let -- patch in supplied DHT key 289 let -- patch in supplied DHT key
393 crypto1 = fromMaybe crypto0 $do 290 crypto1 = fromMaybe crypto0 $do
394 k <- suppliedDHTKey 291 k <- suppliedDHTKey
@@ -409,6 +306,7 @@ newToxOverTransport keydb addr mbSessionsState suppliedDHTKey udp = do
409 mkrouting <- DHT.newRouting addr crypto updateIP updateIP 306 mkrouting <- DHT.newRouting addr crypto updateIP updateIP
410 orouter <- newOnionRouter $ dput XRoutes 307 orouter <- newOnionRouter $ dput XRoutes
411 (cryptonet,dhtcrypt,onioncrypt,dtacrypt,handshakes) <- toxTransport crypto orouter lookupClose udp 308 (cryptonet,dhtcrypt,onioncrypt,dtacrypt,handshakes) <- toxTransport crypto orouter lookupClose udp
309 sessions <- initSessions (sendMessage cryptonet)
412 310
413 let dhtnet0 = layerTransportM (DHT.decrypt crypto) (DHT.encrypt crypto) dhtcrypt 311 let dhtnet0 = layerTransportM (DHT.decrypt crypto) (DHT.encrypt crypto) dhtcrypt
414 tbl4 = DHT.routing4 $ mkrouting (error "missing client") 312 tbl4 = DHT.routing4 $ mkrouting (error "missing client")
@@ -417,22 +315,12 @@ newToxOverTransport keydb addr mbSessionsState suppliedDHTKey udp = do
417 $ \client net -> onInbound (DHT.updateRouting client (mkrouting client) orouter) net 315 $ \client net -> onInbound (DHT.updateRouting client (mkrouting client) orouter) net
418 316
419 hscache <- newHandshakeCache crypto (sendMessage handshakes) 317 hscache <- newHandshakeCache crypto (sendMessage handshakes)
420 318 let sparams = SessionParams
421 let sessionsState = sessionsState0 { sendHandshake = sendMessage handshakes 319 { spCrypto = crypto
422 , sendSessionPacket = sendMessage cryptonet 320 , spSessions = sessions
423 , transportCrypto = crypto 321 , spGetSentHandshake = getSentHandshake hscache
424 -- ToxContact -> STM Policy 322 , spOnNewSession = onNewSession roster addr
425 , netCryptoPolicyByKey = policylookup 323 }
426 }
427 policylookup (ToxContact me them) = do
428 macnt <- HashMap.lookup me <$> readTVar (accounts roster)
429 case macnt of
430 Nothing -> return RefusingToConnect
431 Just acnt -> do
432 mc <- HashMap.lookup them <$> readTVar (contacts acnt)
433 case mc of
434 Nothing -> return RefusingToConnect
435 Just c -> fromMaybe RefusingToConnect <$> readTVar (contactPolicy c)
436 324
437 orouter' <- forkRouteBuilder orouter 325 orouter' <- forkRouteBuilder orouter
438 $ \nid ni -> fmap (\(_,ns,_)->ns) 326 $ \nid ni -> fmap (\(_,ns,_)->ns)
@@ -453,10 +341,9 @@ newToxOverTransport keydb addr mbSessionsState suppliedDHTKey udp = do
453 { toxDHT = dhtclient 341 { toxDHT = dhtclient
454 , toxOnion = onionclient 342 , toxOnion = onionclient
455 , toxToRoute = onInbound (updateContactInfo roster) dtacrypt 343 , toxToRoute = onInbound (updateContactInfo roster) dtacrypt
456 , toxCrypto = addHandler (dput XMisc) (sessionPacketH sessionsState) cryptonet 344 , toxCrypto = addHandler (dput XMisc) (sessionHandler sessions) cryptonet
457 , toxHandshakes = addHandler (dput XMisc) (handshakeH sessionsState) handshakes 345 , toxHandshakes = addHandler (dput XMisc) (handshakeH sparams) handshakes
458 , toxHandshakeCache = hscache 346 , toxHandshakeCache = hscache
459 , toxCryptoSessions = sessionsState
460 , toxCryptoKeys = crypto 347 , toxCryptoKeys = crypto
461 , toxRouting = mkrouting dhtclient 348 , toxRouting = mkrouting dhtclient
462 , toxTokens = toks 349 , toxTokens = toks
@@ -526,8 +413,10 @@ announceToLan sock nid = do
526 (Just "33445") 413 (Just "33445")
527 let broadcast = addrAddress broadcast_info 414 let broadcast = addrAddress broadcast_info
528 bs = S.runPut $ DHT.putMessage (DHT.DHTLanDiscovery nid) 415 bs = S.runPut $ DHT.putMessage (DHT.DHTLanDiscovery nid)
416 dput XLan $ show broadcast ++ " <-- LanAnnounce " ++ show nid
529 saferSendTo sock bs broadcast 417 saferSendTo sock bs broadcast
530 418
419
531toxQSearch :: Tox extra -> Search NodeId (IP, PortNumber) Nonce32 NodeInfo Onion.Rendezvous 420toxQSearch :: Tox extra -> Search NodeId (IP, PortNumber) Nonce32 NodeInfo Onion.Rendezvous
532toxQSearch tox = Onion.toxidSearch (onionTimeout tox) (toxCryptoKeys tox) (toxOnion tox) 421toxQSearch tox = Onion.toxidSearch (onionTimeout tox) (toxCryptoKeys tox) (toxOnion tox)
533 422