diff options
author | Joe Crayne <joe@jerkface.net> | 2018-09-08 06:37:10 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2018-11-03 10:23:45 -0400 |
commit | 36cd21f0b42c09cbcf3a215afbcd754cc37d1c4e (patch) | |
tree | 548a3c6eb5c03692327f561a6d5afbcf3c1d5f4e /src/Network/Tox.hs | |
parent | 0c7768ba8eb62a6a74176f737a1c9c42308d5a8c (diff) |
Switched to new session tracker.
Diffstat (limited to 'src/Network/Tox.hs')
-rw-r--r-- | src/Network/Tox.hs | 165 |
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 | |||
32 | import qualified Data.ByteString.Char8 as C8 | 32 | import qualified Data.ByteString.Char8 as C8 |
33 | import Data.Data | 33 | import Data.Data |
34 | import Data.Functor.Contravariant | 34 | import Data.Functor.Contravariant |
35 | import Data.IP | ||
36 | import Data.Maybe | 35 | import Data.Maybe |
37 | import qualified Data.MinMaxPSQ as MinMaxPSQ | 36 | import qualified Data.MinMaxPSQ as MinMaxPSQ |
38 | import qualified Data.Serialize as S | 37 | import qualified Data.Serialize as S |
39 | import Data.Time.Clock.POSIX (getPOSIXTime) | 38 | import Data.Time.Clock.POSIX (getPOSIXTime) |
40 | import Data.Word | 39 | import Data.Word |
40 | import Network.Socket | ||
41 | import System.Endian | ||
42 | |||
43 | import Network.BitTorrent.DHT.Token as Token | ||
41 | import qualified Data.Wrapper.PSQ as PSQ | 44 | import qualified Data.Wrapper.PSQ as PSQ |
42 | import System.Global6 | 45 | import System.Global6 |
43 | import Network.Address (WantIP (..)) | 46 | import Network.Address (WantIP (..),IP) |
44 | import qualified Network.Kademlia.Routing as R | 47 | import qualified Network.Kademlia.Routing as R |
45 | import Network.QueryResponse | 48 | import Network.QueryResponse |
46 | import Network.Socket | ||
47 | import System.Endian | ||
48 | import Network.BitTorrent.DHT.Token as Token | ||
49 | |||
50 | import Connection | ||
51 | import Crypto.Tox | 49 | import Crypto.Tox |
52 | import Data.Word64Map (fitsInInt) | 50 | import Data.Word64Map (fitsInInt) |
53 | import qualified Data.Word64Map (empty) | 51 | import qualified Data.Word64Map (empty) |
54 | import HandshakeCache | ||
55 | import Network.Kademlia.Bootstrap (forkPollForRefresh, bootstrap) | 52 | import Network.Kademlia.Bootstrap (forkPollForRefresh, bootstrap) |
56 | import Network.Kademlia.Search | ||
57 | import Network.Tox.Crypto.Transport (Handshake(..),CryptoPacket) | 53 | import Network.Tox.Crypto.Transport (Handshake(..),CryptoPacket) |
58 | import Network.Tox.Handshake | ||
59 | import Network.Tox.Crypto.Handlers | ||
60 | import qualified Network.Tox.DHT.Handlers as DHT | 54 | import qualified Network.Tox.DHT.Handlers as DHT |
61 | import qualified Network.Tox.DHT.Transport as DHT | 55 | import qualified Network.Tox.DHT.Transport as DHT |
62 | import Network.Tox.NodeId | 56 | import Network.Tox.NodeId |
@@ -66,12 +60,12 @@ import Network.Tox.Transport | |||
66 | import OnionRouter | 60 | import OnionRouter |
67 | import Network.Tox.ContactInfo | 61 | import Network.Tox.ContactInfo |
68 | import Text.XXD | 62 | import Text.XXD |
69 | import qualified Data.HashMap.Strict as HashMap | ||
70 | import qualified Data.Map.Strict as Map | ||
71 | import DPut | 63 | import DPut |
72 | import Network.Tox.Avahi | 64 | import Network.Tox.Avahi |
73 | import Text.Printf | 65 | import Network.Tox.Session |
74 | import Data.List | 66 | import Network.SessionTransports |
67 | import Network.Kademlia.Search | ||
68 | import HandshakeCache | ||
75 | 69 | ||
76 | newCrypto :: IO TransportCrypto | 70 | newCrypto :: IO TransportCrypto |
77 | newCrypto = do | 71 | newCrypto = 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 | |
221 | netCrypto :: Tox extra -> SecretKey -> PublicKey{-UserKey -} -> IO [NetCryptoSession] | ||
222 | netCrypto tox myseckey theirpubkey = netCryptoWithBackoff 1000000 tox myseckey theirpubkey | ||
223 | |||
224 | -- | helper for 'netCrypto', initiate a netcrypto session, retry after specified millisecs | ||
225 | netCryptoWithBackoff :: Int -> Tox extra -> SecretKey -> PublicKey -> IO [NetCryptoSession] | ||
226 | netCryptoWithBackoff 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. |
313 | getContactInfo :: Tox extra -> IO DHT.DHTPublicKey | 216 | getContactInfo :: Tox extra -> IO DHT.DHTPublicKey |
@@ -365,30 +268,24 @@ getOnionAlias crypto dhtself remoteNode = atomically $ do | |||
365 | 268 | ||
366 | newTox :: TVar Onion.AnnouncedKeys -- ^ Store of announced keys we are a rendezvous for. | 269 | newTox :: 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) |
371 | newTox keydb addr mbSessionsState suppliedDHTKey = do | 274 | newTox 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'. |
377 | newToxOverTransport :: TVar Onion.AnnouncedKeys | 280 | newToxOverTransport :: 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) |
383 | newToxOverTransport keydb addr mbSessionsState suppliedDHTKey udp = do | 286 | newToxOverTransport 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 | |||
531 | toxQSearch :: Tox extra -> Search NodeId (IP, PortNumber) Nonce32 NodeInfo Onion.Rendezvous | 420 | toxQSearch :: Tox extra -> Search NodeId (IP, PortNumber) Nonce32 NodeInfo Onion.Rendezvous |
532 | toxQSearch tox = Onion.toxidSearch (onionTimeout tox) (toxCryptoKeys tox) (toxOnion tox) | 421 | toxQSearch tox = Onion.toxidSearch (onionTimeout tox) (toxCryptoKeys tox) (toxOnion tox) |
533 | 422 | ||