summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/dhtd.hs9
-rw-r--r--src/Network/Tox/Crypto/Handlers.hs275
2 files changed, 188 insertions, 96 deletions
diff --git a/examples/dhtd.hs b/examples/dhtd.hs
index 553146f7..fdbe7719 100644
--- a/examples/dhtd.hs
+++ b/examples/dhtd.hs
@@ -1369,12 +1369,12 @@ ioToSource !action !onEOF = liftIO action >>= \case
1369 ioToSource action onEOF 1369 ioToSource action onEOF
1370 1370
1371newXmmpSink :: Tox.NetCryptoSession -> C.Sink (Flush Tox.CryptoMessage) IO () 1371newXmmpSink :: Tox.NetCryptoSession -> C.Sink (Flush Tox.CryptoMessage) IO ()
1372newXmmpSink session@(Tox.NCrypto { ncOutgoingQueue, ncPacketQueue }) = C.awaitForever $ \flush_cyptomessage -> do 1372newXmmpSink session@(Tox.NCrypto { ncOutgoingQueue = Tox.HaveHandshake outq, ncPacketQueue }) = C.awaitForever $ \flush_cyptomessage -> do
1373 let sendit :: Tox.NetCryptoSession -> Flush Tox.CryptoMessage -> IO () 1373 let sendit :: Tox.NetCryptoSession -> Flush Tox.CryptoMessage -> IO ()
1374 sendit session (Chunk msg) = do 1374 sendit session (Chunk msg) = do
1375 extra <- readyOutGoing ncOutgoingQueue 1375 extra <- readyOutGoing outq
1376 r <- atomically $ do 1376 r <- atomically $ do
1377 rTry <- tryAppendQueueOutgoing extra ncOutgoingQueue msg 1377 rTry <- tryAppendQueueOutgoing extra outq msg
1378 case rTry of 1378 case rTry of
1379 OGFull -> retry 1379 OGFull -> retry
1380 OGSuccess -> return OGSuccess 1380 OGSuccess -> return OGSuccess
@@ -1899,7 +1899,8 @@ main = runResourceT $ liftBaseWith $ \resT -> do
1899 xmppSrc = ioToSource receiveCrypto onEOF 1899 xmppSrc = ioToSource receiveCrypto onEOF
1900 xmppSink = newXmmpSink netcrypto 1900 xmppSink = newXmmpSink netcrypto
1901 forM_ msv $ \sv -> do 1901 forM_ msv $ \sv -> do
1902 announceToxJabberPeer (Tox.ncTheirPublicKey netcrypto) (xmppEventChannel sv) addrTox (Tox.ncSockAddr netcrypto) pingflag xmppSrc xmppSink 1902 let Tox.HaveDHTKey saddr = Tox.ncSockAddr netcrypto
1903 announceToxJabberPeer (Tox.ncTheirPublicKey netcrypto) (xmppEventChannel sv) addrTox saddr pingflag xmppSrc xmppSink
1903 -- TODO: Update toxContactInfo, connected. 1904 -- TODO: Update toxContactInfo, connected.
1904 atomically $ do 1905 atomically $ do
1905 supply <- readTVar (Tox.listenerIDSupply netCryptoSessionsState) 1906 supply <- readTVar (Tox.listenerIDSupply netCryptoSessionsState)
diff --git a/src/Network/Tox/Crypto/Handlers.hs b/src/Network/Tox/Crypto/Handlers.hs
index 2f8b059a..bcca65e6 100644
--- a/src/Network/Tox/Crypto/Handlers.hs
+++ b/src/Network/Tox/Crypto/Handlers.hs
@@ -1,6 +1,7 @@
1{-# LANGUAGE NamedFieldPuns #-} 1{-# LANGUAGE NamedFieldPuns #-}
2{-# LANGUAGE TupleSections #-} 2{-# LANGUAGE TupleSections #-}
3{-# LANGUAGE TypeOperators #-} 3{-# LANGUAGE TypeOperators #-}
4{-# LANGUAGE DeriveFunctor #-}
4module Network.Tox.Crypto.Handlers where 5module Network.Tox.Crypto.Handlers where
5 6
6import Network.QueryResponse 7import Network.QueryResponse
@@ -50,23 +51,72 @@ import Debug.Trace
50import Text.Printf 51import Text.Printf
51import Data.Bool 52import Data.Bool
52 53
54
55-- * These types are isomorphic to Maybe, but have the advantage of documenting
56-- when an item is expected to become known.
57data UponDHTKey a = NeedDHTKey | HaveDHTKey a deriving (Functor,Show,Eq)
58data UponCookie a = NeedCookie | HaveCookie a deriving (Functor,Show,Eq)
59data UponHandshake a = NeedHandshake | HaveHandshake a deriving (Functor,Show,Eq)
60data UponCryptoPacket a = NeedCryptoPacket | HaveCryptoPacket a deriving (Functor,Show,Eq)
61
53-- util, todo: move to another module 62-- util, todo: move to another module
54maybeToEither :: Maybe b -> Either String b 63maybeToEither :: AsMaybe f => f b -> Either String b
55maybeToEither (Just x) = Right x 64maybeToEither y | Just x <- toMaybe y = Right x
56maybeToEither Nothing = Left "maybeToEither" 65maybeToEither _ = Left "maybeToEither"
66
67-- | type class encoding of isomorphism to Maybe
68class AsMaybe f where
69 toMaybe :: f a -> Maybe a
70 -- | The o in from is left out so as not to colide with 'Data.Maybe.fromMaybe'
71 frmMaybe :: Maybe a -> f a
72
73instance AsMaybe Maybe where
74 toMaybe x = x
75 frmMaybe x = x
76
77instance AsMaybe UponDHTKey where
78 toMaybe NeedDHTKey = Nothing
79 toMaybe (HaveDHTKey x) = Just x
80 frmMaybe Nothing = NeedDHTKey
81 frmMaybe (Just x) = HaveDHTKey x
82
83instance AsMaybe UponCookie where
84 toMaybe NeedCookie = Nothing
85 toMaybe (HaveCookie x) = Just x
86 frmMaybe Nothing = NeedCookie
87 frmMaybe (Just x) = HaveCookie x
88
89instance AsMaybe UponHandshake where
90 toMaybe NeedHandshake = Nothing
91 toMaybe (HaveHandshake x) = Just x
92 frmMaybe Nothing = NeedHandshake
93 frmMaybe (Just x) = HaveHandshake x
94
95instance AsMaybe UponCryptoPacket where
96 toMaybe NeedCryptoPacket = Nothing
97 toMaybe (HaveCryptoPacket x) = Just x
98 frmMaybe Nothing = NeedCryptoPacket
99 frmMaybe (Just x) = HaveCryptoPacket x
100
57 101
58data NetCryptoSessionStatus = Unaccepted | Accepted {- InProgress AwaitingSessionPacket -} | Confirmed {- Established -} 102data NetCryptoSessionStatus = Unaccepted | Accepted {- InProgress AwaitingSessionPacket -} | Confirmed {- Established -}
59 deriving (Eq,Ord,Show,Enum) 103 deriving (Eq,Ord,Show,Enum)
60 104
61 105
106-- | The idea of IOHook is to replicate the familiar pattern
107-- where a function returns Nothing to consume a value
108-- or a function used to modify the value and pass it
109-- to be processed by another hook.
62type IOHook addr x = addr -> x -> IO (Maybe (x -> x)) 110type IOHook addr x = addr -> x -> IO (Maybe (x -> x))
111
112-- | NetCryptoHook's use the Session as their 'addr' and the
113-- value they consume or modify is CryptoMessage.
63type NetCryptoHook = IOHook NetCryptoSession CryptoMessage 114type NetCryptoHook = IOHook NetCryptoSession CryptoMessage
115
116-- | Convert an id byte to it's type (in Word64 format)
117-- Although the type doesn't enforce it, MsgTypeArray
118-- should always have 256 entries.
64type MsgTypeArray = A.UArray Word8 Word64 119type MsgTypeArray = A.UArray Word8 Word64
65-- type MsgOutMap = RangeMap STArray Word8 STRef
66-- type MsgOutMap = W64.Word64Map Word8
67-- type MsgOutMap = A.UArray Word64 Word8 -- if above is too slow, switch to this, but use reasonable bounds
68-- msgOutMapLookup :: Word64 -> MsgOutMap -> STM (Maybe Word8)
69-- msgOutMapLookup k mp = return (W64.lookup k mp)
70 120
71-- | Information, that may be made visible in multiple sessions, as well 121-- | Information, that may be made visible in multiple sessions, as well
72-- as displayed in some way to the user via mutiple views. 122-- as displayed in some way to the user via mutiple views.
@@ -168,36 +218,65 @@ data NetCryptoSession = NCrypto
168 , ncMyPublicKey :: PublicKey 218 , ncMyPublicKey :: PublicKey
169 , ncSessionId :: SessionID 219 , ncSessionId :: SessionID
170 , ncTheirPublicKey :: PublicKey -- Tox id w/o nospam 220 , ncTheirPublicKey :: PublicKey -- Tox id w/o nospam
171 , ncTheirBaseNonce :: TVar Nonce24 -- base nonce + packet number 221 , ncTheirBaseNonce :: TVar (UponHandshake Nonce24) -- base nonce + packet number
172 , ncMyPacketNonce :: TVar Nonce24 -- base nonce + packet number 222 , ncMyPacketNonce :: TVar Nonce24 -- base nonce + packet number
173 , ncHandShake :: TVar (Maybe (Handshake Encrypted)) 223 , ncHandShake :: TVar (UponHandshake (Handshake Encrypted))
174 , ncCookie :: TVar (Maybe Cookie) -- ^ Cookie issued by remote peer 224 , ncCookie :: TVar (UponCookie Cookie) -- ^ Cookie issued by remote peer
175 , ncTheirDHTKey :: PublicKey 225 , ncTheirDHTKey :: UponDHTKey PublicKey
176 , ncTheirSessionPublic :: Maybe PublicKey 226 , ncTheirSessionPublic :: UponHandshake PublicKey
177 , ncSessionSecret :: SecretKey 227 , ncSessionSecret :: SecretKey
178 , ncSockAddr :: SockAddr 228 , ncSockAddr :: UponDHTKey SockAddr
229 -- The remaining fields correspond to implementation specific state --
230 -- where as the prior fields will be used in any implementation --
179 , ncHooks :: TVar (Map.Map MessageType [NetCryptoHook]) 231 , ncHooks :: TVar (Map.Map MessageType [NetCryptoHook])
180 , ncUnrecognizedHook :: TVar (MessageType -> NetCryptoHook) 232 , ncUnrecognizedHook :: TVar (MessageType -> NetCryptoHook)
181 , ncIncomingTypeArray :: TVar MsgTypeArray -- ^ supported messages, 0 for unsupported, 233 , ncIncomingTypeArray :: TVar MsgTypeArray
182 -- otherwise the messageType, some message types 234 -- ^ This array maps 255 Id bytes to MessageType
183 -- may not be in ncHooks yet, but they should appear 235 -- It should contain all messages this session understands.
184 -- here if ncUnrecognizedHook will add them to ncHooks 236 -- Use 0 for unsupported. It is used when a message comes
185 -- on an as-need basis. 237 -- in, and should ordinarily be the identity map.
238 --
239 -- Id's 0xC7 and 0x63 should contain range-specifying types only, if
240 -- such things come to be defined, because these MessageId's are
241 -- always escapes.
242 --
243 -- Currently, the values at these indices are ignored.
186 , ncOutgoingIdMap :: RangeMap TArray Word8 TVar 244 , ncOutgoingIdMap :: RangeMap TArray Word8 TVar
187 -- ^ used to lookup the outgoing id for a type, for now always an identity map 245 -- ^ used to lookup the outgoing id for a type when sending an outoing message
188 -- TODO: need 2 more outgoing id maps for escape-lossy and escape-lossless (group msgs) 246 , ncOutgoingIdMapEscapedLossy :: TVar (A.Array Word8 Word8)
189 , ncAllSessions :: NetCryptoSessions -- ^ may be needed if one net-crypto session 247 -- ^ mapping of secondary id, when primary id is 0xC7
190 -- needs to possibly start another, as is 248 -- (These Id's are called 'MessageName' in 'Network.Tox.Crypto.Transport')
191 -- the case in group chats 249 -- used when sending an outoing message
250 , ncOutgoingIdMapEscapedLossless :: TVar (A.Array Word8 Word8)
251 -- ^ mapping of secondary id, when primary id is 0x63
252 -- (These Id's are called 'MessageName' in 'Network.Tox.Crypto.Transport')
253 -- used when sending an outoing message
254 , ncAllSessions :: NetCryptoSessions
255 -- ^ needed if one net-crypto session
256 -- needs to possibly start another, as is
257 -- the case in group chats
192 , ncView :: TVar SessionView 258 , ncView :: TVar SessionView
259 -- ^ contains your nick, status etc
193 , ncPacketQueue :: PacketQueue CryptoData 260 , ncPacketQueue :: PacketQueue CryptoData
194 , ncBufferStart :: TVar Word32 261 -- ^ a buffer in which incoming packets may be stored out of order
262 -- but from which they may be extracted in sequence,
263 -- helps ensure lossless packets are processed in order
195 , ncDequeueThread :: Maybe ThreadId 264 , ncDequeueThread :: Maybe ThreadId
265 -- ^ when the thread which dequeues from ncPacketQueue
266 -- is started, its ThreadId is stored here
196 , ncPingMachine :: Maybe PingMachine 267 , ncPingMachine :: Maybe PingMachine
197 , ncOutgoingQueue :: PQ.PacketOutQueue (State,Nonce24,RangeMap TArray Word8 TVar) 268 -- ^ when the ping thread is started, store it here
198 CryptoMessage 269 , ncOutgoingQueue :: UponHandshake
199 (CryptoPacket Encrypted) 270 (PQ.PacketOutQueue
200 CryptoData 271 (State,Nonce24,RangeMap TArray Word8 TVar)
272 CryptoMessage
273 (CryptoPacket Encrypted)
274 CryptoData)
275 -- ^ To send a message add it to this queue, by calling 'tryAppendQueueOutgoing'
276 -- but remember to call 'readyOutGoing' first, because the shared secret cache
277 -- presently requires the IO monad.
278 -- This specialized queue handles setting buffer_start and buffer_end and encrypting
279 -- 'readyOutGoing' provides the first parameter to 'tryAppendQueueOutgoing'
201 , ncLastNMsgs :: CyclicBuffer (Bool{-Handled?-},(ViewSnapshot,InOrOut CryptoMessage)) 280 , ncLastNMsgs :: CyclicBuffer (Bool{-Handled?-},(ViewSnapshot,InOrOut CryptoMessage))
202 -- ^ cyclic buffer, holds the last N non-handshake crypto messages 281 -- ^ cyclic buffer, holds the last N non-handshake crypto messages
203 -- even if there is no attached user interface. 282 -- even if there is no attached user interface.
@@ -222,6 +301,7 @@ data NetCryptoSessions = NCSessions
222 , listenerIDSupply :: TVar Supply 301 , listenerIDSupply :: TVar Supply
223 } 302 }
224 303
304-- | This is the type of a hook to run when a session is created.
225type NewSessionHook = IOHook (Maybe NoSpam) NetCryptoSession 305type NewSessionHook = IOHook (Maybe NoSpam) NetCryptoSession
226 306
227addNewSessionHook :: NetCryptoSessions -> NewSessionHook -> STM () 307addNewSessionHook :: NetCryptoSessions -> NewSessionHook -> STM ()
@@ -229,7 +309,7 @@ addNewSessionHook allsessions@(NCSessions { announceNewSessionHooks }) hook = mo
229 309
230forgetCrypto :: TransportCrypto -> NetCryptoSessions -> NetCryptoSession -> STM () 310forgetCrypto :: TransportCrypto -> NetCryptoSessions -> NetCryptoSession -> STM ()
231forgetCrypto crypto (NCSessions {netCryptoSessions,netCryptoSessionsByKey}) session = do 311forgetCrypto crypto (NCSessions {netCryptoSessions,netCryptoSessionsByKey}) session = do
232 let addr = ncSockAddr session 312 let HaveDHTKey addr = ncSockAddr session
233 sid = ncSessionId session 313 sid = ncSessionId session
234 sPubKey = ncTheirPublicKey session 314 sPubKey = ncTheirPublicKey session
235 byAddrMap <- readTVar netCryptoSessions 315 byAddrMap <- readTVar netCryptoSessions
@@ -305,7 +385,7 @@ data HandshakeParams
305 = HParam 385 = HParam
306 { hpTheirBaseNonce :: Maybe Nonce24 -- ignore and generate your own 386 { hpTheirBaseNonce :: Maybe Nonce24 -- ignore and generate your own
307 , hpOtherCookie :: Cookie 387 , hpOtherCookie :: Cookie
308 , hpTheirSessionKeyPublic :: PublicKey 388 , hpTheirSessionKeyPublic :: Maybe PublicKey
309 , hpMySecretKey :: SecretKey 389 , hpMySecretKey :: SecretKey
310 , hpCookieRemotePubkey :: PublicKey 390 , hpCookieRemotePubkey :: PublicKey
311 , hpCookieRemoteDhtkey :: PublicKey 391 , hpCookieRemoteDhtkey :: PublicKey
@@ -409,9 +489,9 @@ freshCryptoSession :: NetCryptoSessions -> SockAddr -> HandshakeParams -> IO ()
409freshCryptoSession sessions 489freshCryptoSession sessions
410 addr 490 addr
411 hp@(HParam 491 hp@(HParam
412 { hpTheirBaseNonce = Just theirBaseNonce 492 { hpTheirBaseNonce = mbtheirBaseNonce
413 , hpOtherCookie = otherCookie 493 , hpOtherCookie = otherCookie
414 , hpTheirSessionKeyPublic = theirSessionKey 494 , hpTheirSessionKeyPublic = mbtheirSessionKey
415 , hpMySecretKey = key 495 , hpMySecretKey = key
416 , hpCookieRemotePubkey = remotePublicKey 496 , hpCookieRemotePubkey = remotePublicKey
417 , hpCookieRemoteDhtkey = remoteDhtPublicKey 497 , hpCookieRemoteDhtkey = remoteDhtPublicKey
@@ -424,7 +504,7 @@ freshCryptoSession sessions
424 modifyTVar (nextSessionId sessions) (+1) 504 modifyTVar (nextSessionId sessions) (+1)
425 return x 505 return x
426 ncState0 <- atomically $ newTVar Accepted -- (InProgress AwaitingSessionPacket) 506 ncState0 <- atomically $ newTVar Accepted -- (InProgress AwaitingSessionPacket)
427 ncTheirBaseNonce0 <- atomically $ newTVar theirBaseNonce 507 ncTheirBaseNonce0 <- atomically $ newTVar (frmMaybe mbtheirBaseNonce)
428 n24 <- atomically $ transportNewNonce crypto 508 n24 <- atomically $ transportNewNonce crypto
429 state <- lookupSharedSecret crypto key remotePublicKey n24 509 state <- lookupSharedSecret crypto key remotePublicKey n24
430 newBaseNonce <- atomically $ transportNewNonce crypto 510 newBaseNonce <- atomically $ transportNewNonce crypto
@@ -437,17 +517,17 @@ freshCryptoSession sessions
437 , handshakeData = encrypted 517 , handshakeData = encrypted
438 } 518 }
439 let myhandshake= encodeHandshake <$> mbMyhandshakeData 519 let myhandshake= encodeHandshake <$> mbMyhandshakeData
440 ncHandShake0 <- atomically $ newTVar myhandshake 520 ncHandShake0 <- atomically $ newTVar (frmMaybe myhandshake)
441 forM myhandshake $ \response_handshake -> do 521 forM myhandshake $ \response_handshake -> do
442 sendMessage (sessionTransport sessions) addr (NetHandshake response_handshake) 522 sendMessage (sessionTransport sessions) addr (NetHandshake response_handshake)
443 ncMyPacketNonce0 <- atomically $ newTVar newBaseNonce 523 ncMyPacketNonce0 <- atomically $ newTVar newBaseNonce
444 cookie0 <- atomically $ newTVar (Just otherCookie) 524 cookie0 <- atomically $ newTVar (HaveCookie otherCookie)
445 newsession <- generateSecretKey 525 newsession <- generateSecretKey
446 ncHooks0 <- atomically $ newTVar (defaultHooks sessions) 526 ncHooks0 <- atomically $ newTVar (defaultHooks sessions)
447 ncUnrecognizedHook0 <- atomically $ newTVar (defaultUnrecognizedHook sessions) 527 ncUnrecognizedHook0 <- atomically $ newTVar (defaultUnrecognizedHook sessions)
448 ncIncomingTypeArray0 <- atomically $ newTVar (msgTypeArray sessions) 528 ncIncomingTypeArray0 <- atomically $ newTVar (msgTypeArray sessions)
449 let idMap = foldl (\mp (x,y) -> W64.insert x y mp) W64.empty (zip [0..255] [0..255]) 529 let idMap = foldl (\mp (x,y) -> W64.insert x y mp) W64.empty (zip [0..255] [0..255])
450 ncOutgoingIdMap0 <- atomically $ do 530 (ncOutgoingIdMap0,lossyEscapeIdMap,losslessEscapeIdMap) <- atomically $ do
451 idmap <- emptySTMRangeMap 531 idmap <- emptySTMRangeMap
452 insertArrayAt idmap 0 (A.listArray (0,255) [0 .. 255]) 532 insertArrayAt idmap 0 (A.listArray (0,255) [0 .. 255])
453 -- the 2 escape ranges are adjacent, so put them in one array: 533 -- the 2 escape ranges are adjacent, so put them in one array:
@@ -456,18 +536,25 @@ freshCryptoSession sessions
456 )) 536 ))
457 -- lossless as separate range could have been done: 537 -- lossless as separate range could have been done:
458 -- > insertArrayAt idmap 768 (A.listArray (768,1023) (replicate 256 0x63)) 538 -- > insertArrayAt idmap 768 (A.listArray (768,1023) (replicate 256 0x63))
459 return idmap 539 lossyEsc <- newTVar $ A.listArray (0,255) [0 .. 255]
540 losslessEsc <- newTVar $ A.listArray (0,255) [0 .. 255]
541 return (idmap,lossyEsc,losslessEsc)
460 ncView0 <- atomically $ newTVar (sessionView sessions) 542 ncView0 <- atomically $ newTVar (sessionView sessions)
461 pktq <- atomically $ PQ.new (inboundQueueCapacity sessions) 0 543 pktq <- atomically $ PQ.new (inboundQueueCapacity sessions) 0
462 bufstart <- atomically $ newTVar 0 544 bufstart <- atomically $ newTVar 0
463 let toWireIO = do 545 mbpktoq
464 f <- lookupNonceFunction crypto newsession theirSessionKey 546 <- case mbtheirSessionKey of
465 atomically $ do 547 Nothing -> return NeedHandshake
466 n24 <- readTVar ncMyPacketNonce0 548 Just theirSessionKey -> do
467 let n24plus1 = incrementNonce24 n24 549 let toWireIO = do
468 writeTVar ncMyPacketNonce0 n24plus1 550 f <- lookupNonceFunction crypto newsession theirSessionKey
469 return (return (f n24, n24, ncOutgoingIdMap0)) 551 atomically $ do
470 pktoq <- atomically $ PQ.newOutGoing pktq ncToWire toWireIO 0 (outboundQueueCapacity sessions) 0 552 n24 <- readTVar ncMyPacketNonce0
553 let n24plus1 = incrementNonce24 n24
554 writeTVar ncMyPacketNonce0 n24plus1
555 return (return (f n24, n24, ncOutgoingIdMap0))
556 pktoq <- atomically $ PQ.newOutGoing pktq ncToWire toWireIO 0 (outboundQueueCapacity sessions) 0
557 return (HaveHandshake pktoq)
471 lastNQ <- atomically (CB.new 10 0 :: STM (CyclicBuffer (Bool,(ViewSnapshot,InOrOut CryptoMessage)))) 558 lastNQ <- atomically (CB.new 10 0 :: STM (CyclicBuffer (Bool,(ViewSnapshot,InOrOut CryptoMessage))))
472 listeners <- atomically $ newTVar IntMap.empty 559 listeners <- atomically $ newTVar IntMap.empty
473 msgNum <- atomically $ newTVar 0 560 msgNum <- atomically $ newTVar 0
@@ -481,21 +568,22 @@ freshCryptoSession sessions
481 , ncMyPacketNonce = ncMyPacketNonce0 568 , ncMyPacketNonce = ncMyPacketNonce0
482 , ncHandShake = ncHandShake0 569 , ncHandShake = ncHandShake0
483 , ncCookie = cookie0 570 , ncCookie = cookie0
484 , ncTheirDHTKey = remoteDhtPublicKey 571 , ncTheirDHTKey = HaveDHTKey remoteDhtPublicKey
485 , ncTheirSessionPublic = Just theirSessionKey 572 , ncTheirSessionPublic = frmMaybe mbtheirSessionKey
486 , ncSessionSecret = newsession 573 , ncSessionSecret = newsession
487 , ncSockAddr = addr 574 , ncSockAddr = HaveDHTKey addr
488 , ncHooks = ncHooks0 575 , ncHooks = ncHooks0
489 , ncUnrecognizedHook = ncUnrecognizedHook0 576 , ncUnrecognizedHook = ncUnrecognizedHook0
490 , ncAllSessions = sessions 577 , ncAllSessions = sessions
491 , ncIncomingTypeArray = ncIncomingTypeArray0 578 , ncIncomingTypeArray = ncIncomingTypeArray0
492 , ncOutgoingIdMap = ncOutgoingIdMap0 579 , ncOutgoingIdMap = ncOutgoingIdMap0
580 , ncOutgoingIdMapEscapedLossy = lossyEscapeIdMap
581 , ncOutgoingIdMapEscapedLossless = losslessEscapeIdMap
493 , ncView = ncView0 582 , ncView = ncView0
494 , ncPacketQueue = pktq 583 , ncPacketQueue = pktq
495 , ncBufferStart = bufstart
496 , ncDequeueThread = Nothing -- error "you want the NetCrypto-Dequeue thread id, but is it started?" 584 , ncDequeueThread = Nothing -- error "you want the NetCrypto-Dequeue thread id, but is it started?"
497 , ncPingMachine = Nothing -- error "you want the NetCrypto-PingMachine, but is it started?" 585 , ncPingMachine = Nothing -- error "you want the NetCrypto-PingMachine, but is it started?"
498 , ncOutgoingQueue = pktoq 586 , ncOutgoingQueue = mbpktoq
499 , ncLastNMsgs = lastNQ 587 , ncLastNMsgs = lastNQ
500 , ncListeners = listeners 588 , ncListeners = listeners
501 } 589 }
@@ -507,37 +595,40 @@ freshCryptoSession sessions
507 cd <- atomically $ PQ.dequeue pktq 595 cd <- atomically $ PQ.dequeue pktq
508 _ <- runCryptoHook (netCryptoSession0 {ncDequeueThread=Just tid}) (bufferData cd) 596 _ <- runCryptoHook (netCryptoSession0 {ncDequeueThread=Just tid}) (bufferData cd)
509 loop 597 loop
510 -- launch dequeueOutgoing thread 598 case mbpktoq of
511 threadidOutgoing <- forkIO $ do 599 NeedHandshake -> return ()
512 tid <- myThreadId 600 HaveHandshake pktoq -> do
513 labelThread tid ("NetCryptoDequeueOutgoing." ++ show (key2id remotePublicKey)) 601 -- launch dequeueOutgoing thread
514 fix $ \loop -> do 602 threadidOutgoing <- forkIO $ do
515 (_,pkt) <- atomically $ PQ.dequeueOutgoing pktoq 603 tid <- myThreadId
516 dput XNetCrypto "NetCryptoDequeueOutgoing thread... Sending encrypted Packet" 604 labelThread tid ("NetCryptoDequeueOutgoing." ++ show (key2id remotePublicKey))
517 sendMessage (sessionTransport sessions) addr (NetCrypto pkt) 605 fix $ \loop -> do
518 loop 606 (_,pkt) <- atomically $ PQ.dequeueOutgoing pktoq
519 -- launch ping thread 607 dput XNetCrypto "NetCryptoDequeueOutgoing thread... Sending encrypted Packet"
520 fuzz <- randomRIO (0,2000) 608 sendMessage (sessionTransport sessions) addr (NetCrypto pkt)
521 pingMachine <- forkPingMachine ("NetCrypto." ++ show (key2id remotePublicKey)) (15000 + fuzz) 2000 609 loop
522 -- update session with thread ids 610 -- launch ping thread
523 let netCryptoSession = netCryptoSession0 {ncDequeueThread=Just threadid, ncPingMachine=Just pingMachine} 611 fuzz <- randomRIO (0,2000)
524 -- add this session to the lookup maps 612 pingMachine <- forkPingMachine ("NetCrypto." ++ show (key2id remotePublicKey)) (15000 + fuzz) 2000
525 atomically $ do 613 -- update session with thread ids
526 modifyTVar allsessions (Map.insert addr netCryptoSession) 614 let netCryptoSession = netCryptoSession0 {ncDequeueThread=Just threadid, ncPingMachine=Just pingMachine}
527 byKeyResult <- readTVar allsessionsByKey >>= return . Map.lookup remotePublicKey 615 -- add this session to the lookup maps
528 case byKeyResult of 616 atomically $ do
529 Nothing -> modifyTVar allsessionsByKey (Map.insert remotePublicKey [netCryptoSession]) 617 modifyTVar allsessions (Map.insert addr netCryptoSession)
530 Just xs -> modifyTVar allsessionsByKey (Map.insert remotePublicKey (netCryptoSession:xs)) 618 byKeyResult <- readTVar allsessionsByKey >>= return . Map.lookup remotePublicKey
531 -- run announceNewSessionHooks 619 case byKeyResult of
532 hooks <- atomically $ readTVar (announceNewSessionHooks sessions) 620 Nothing -> modifyTVar allsessionsByKey (Map.insert remotePublicKey [netCryptoSession])
533 flip fix (hooks,netCryptoSession) $ \loop (hooks,session) -> 621 Just xs -> modifyTVar allsessionsByKey (Map.insert remotePublicKey (netCryptoSession:xs))
534 case hooks of 622 -- run announceNewSessionHooks
535 [] -> return () 623 hooks <- atomically $ readTVar (announceNewSessionHooks sessions)
536 (h:hs) -> do 624 flip fix (hooks,netCryptoSession) $ \loop (hooks,session) ->
537 r <- h Nothing session 625 case hooks of
538 case r of 626 [] -> return ()
539 Just f -> loop (hs, f session) 627 (h:hs) -> do
540 Nothing -> return () 628 r <- h Nothing session
629 case r of
630 Just f -> loop (hs, f session)
631 Nothing -> return ()
541 632
542-- | Called when we get a handshake, but there's already a session entry. 633-- | Called when we get a handshake, but there's already a session entry.
543updateCryptoSession :: NetCryptoSessions -> SockAddr -> HandshakeParams -> NetCryptoSession -> IO () 634updateCryptoSession :: NetCryptoSessions -> SockAddr -> HandshakeParams -> NetCryptoSession -> IO ()
@@ -554,21 +645,21 @@ updateCryptoSession sessions addr hp session = do
554 then do 645 then do
555 dput XNetCrypto "updateCryptoSession already accepted.." 646 dput XNetCrypto "updateCryptoSession already accepted.."
556 dput XNetCrypto (" ncTheirBaseNonce0=" ++ show ncTheirBaseNonce0 647 dput XNetCrypto (" ncTheirBaseNonce0=" ++ show ncTheirBaseNonce0
557 ++ bool "(/=)" "(==)" (Just ncTheirBaseNonce0 == hpTheirBaseNonce hp) 648 ++ bool "(/=)" "(==)" (toMaybe ncTheirBaseNonce0 == hpTheirBaseNonce hp)
558 ++ "hpTheirBaseNonce=" ++ show (hpTheirBaseNonce hp)) 649 ++ "hpTheirBaseNonce=" ++ show (hpTheirBaseNonce hp))
559 dput XNetCrypto (" ncTheirDHTKey=" ++ show (ncTheirDHTKey session) 650 dput XNetCrypto (" ncTheirDHTKey=" ++ show (ncTheirDHTKey session)
560 ++ bool "{/=}" "{==}" (ncTheirDHTKey session == hpCookieRemoteDhtkey hp) 651 ++ bool "{/=}" "{==}" (ncTheirDHTKey session == HaveDHTKey (hpCookieRemoteDhtkey hp))
561 ++ "hpCookieRemoteDhtkey=" ++ show (hpCookieRemoteDhtkey hp)) 652 ++ "hpCookieRemoteDhtkey=" ++ show (hpCookieRemoteDhtkey hp))
562 when ( -- Just ncTheirBaseNonce0 /= hpTheirBaseNonce hp -- XXX: Do we really want to compare base nonce here? 653 when ( -- Just ncTheirBaseNonce0 /= hpTheirBaseNonce hp -- XXX: Do we really want to compare base nonce here?
563 -- || 654 -- ||
564 ncTheirDHTKey session /= hpCookieRemoteDhtkey hp 655 ncTheirDHTKey session /= HaveDHTKey (hpCookieRemoteDhtkey hp)
565 ) $ freshCryptoSession sessions addr hp 656 ) $ freshCryptoSession sessions addr hp
566 else do 657 else do
567 dput XNetCrypto "updateCryptoSession else clause" 658 dput XNetCrypto "updateCryptoSession else clause"
568 dput XNetCrypto (" ncTheirBaseNonce0=" ++ show ncTheirBaseNonce0 659 dput XNetCrypto (" ncTheirBaseNonce0=" ++ show ncTheirBaseNonce0
569 ++ bool "(/=)" "(==)" (Just ncTheirBaseNonce0 == hpTheirBaseNonce hp) 660 ++ bool "(/=)" "(==)" (toMaybe ncTheirBaseNonce0 == hpTheirBaseNonce hp)
570 ++ "hpTheirBaseNonce=" ++ show (hpTheirBaseNonce hp)) 661 ++ "hpTheirBaseNonce=" ++ show (hpTheirBaseNonce hp))
571 if ( Just ncTheirBaseNonce0 /= hpTheirBaseNonce hp) 662 if ( ncTheirBaseNonce0 /= frmMaybe (hpTheirBaseNonce hp))
572 then freshCryptoSession sessions addr hp -- basenonce mismatch, trigger refresh 663 then freshCryptoSession sessions addr hp -- basenonce mismatch, trigger refresh
573 else atomically $ writeTVar (ncState session) Accepted -- (InProgress AwaitingSessionPacket) 664 else atomically $ writeTVar (ncState session) Accepted -- (InProgress AwaitingSessionPacket)
574 665
@@ -622,7 +713,7 @@ cryptoNetHandler sessions addr (NetHandshake (Handshake (Cookie n24 ecookie) non
622 HParam 713 HParam
623 { hpTheirBaseNonce = Just baseNonce 714 { hpTheirBaseNonce = Just baseNonce
624 , hpOtherCookie = otherCookie 715 , hpOtherCookie = otherCookie
625 , hpTheirSessionKeyPublic = sessionKey 716 , hpTheirSessionKeyPublic = Just sessionKey
626 , hpMySecretKey = key 717 , hpMySecretKey = key
627 , hpCookieRemotePubkey = remotePubkey 718 , hpCookieRemotePubkey = remotePubkey
628 , hpCookieRemoteDhtkey = remoteDhtkey 719 , hpCookieRemoteDhtkey = remoteDhtkey
@@ -661,7 +752,7 @@ cryptoNetHandler sessions addr (NetCrypto (CryptoPacket nonce16 encrypted)) = do
661 Just session@(NCrypto { ncIncomingTypeArray, ncState, ncPacketQueue, ncHooks, 752 Just session@(NCrypto { ncIncomingTypeArray, ncState, ncPacketQueue, ncHooks,
662 ncSessionSecret, ncTheirSessionPublic, ncTheirBaseNonce, 753 ncSessionSecret, ncTheirSessionPublic, ncTheirBaseNonce,
663 ncPingMachine}) -> do 754 ncPingMachine}) -> do
664 theirBaseNonce <- atomically $ readTVar ncTheirBaseNonce 755 HaveHandshake theirBaseNonce <- atomically $ readTVar ncTheirBaseNonce
665 -- Try to decrypt message 756 -- Try to decrypt message
666 let diff :: Word16 757 let diff :: Word16
667 diff = nonce16 - (last2Bytes theirBaseNonce) -- truncating to Word16 758 diff = nonce16 - (last2Bytes theirBaseNonce) -- truncating to Word16
@@ -699,11 +790,11 @@ cryptoNetHandler sessions addr (NetCrypto (CryptoPacket nonce16 encrypted)) = do
699 -- update ncTheirBaseNonce if necessary 790 -- update ncTheirBaseNonce if necessary
700 when (diff > 2 * dATA_NUM_THRESHOLD)$ 791 when (diff > 2 * dATA_NUM_THRESHOLD)$
701 atomically $ do 792 atomically $ do
702 y <- readTVar ncTheirBaseNonce 793 HaveHandshake y <- readTVar ncTheirBaseNonce
703 let x = addtoNonce24 y (fromIntegral dATA_NUM_THRESHOLD) 794 let x = addtoNonce24 y (fromIntegral dATA_NUM_THRESHOLD)
704 trace ("nonce y(" ++ show y ++ ") + " ++ show (fromIntegral dATA_NUM_THRESHOLD) 795 trace ("nonce y(" ++ show y ++ ") + " ++ show (fromIntegral dATA_NUM_THRESHOLD)
705 ++ " = " ++ show x) (return ()) 796 ++ " = " ++ show x) (return ())
706 writeTVar ncTheirBaseNonce y 797 writeTVar ncTheirBaseNonce (HaveHandshake y)
707 -- then set session confirmed, 798 -- then set session confirmed,
708 atomically $ writeTVar ncState Confirmed {-Established-} 799 atomically $ writeTVar ncState Confirmed {-Established-}
709 -- bump ping machine 800 -- bump ping machine
@@ -807,7 +898,7 @@ allMsgTypes fDefault = A.listArray (minBound,maxBound) (0:knownMsgs)
807 898
808sendCrypto :: TransportCrypto -> NetCryptoSession -> (STM ()) -> CryptoMessage -> IO (Either String ()) 899sendCrypto :: TransportCrypto -> NetCryptoSession -> (STM ()) -> CryptoMessage -> IO (Either String ())
809sendCrypto crypto session updateLocal cm = do 900sendCrypto crypto session updateLocal cm = do
810 let outq = ncOutgoingQueue session 901 let HaveHandshake outq = ncOutgoingQueue session
811 -- XXX: potential race? if shared secret comes out of sync with cache? 902 -- XXX: potential race? if shared secret comes out of sync with cache?
812 dput XNetCrypto "sendCrypto: enter " 903 dput XNetCrypto "sendCrypto: enter "
813 getOutGoingParam <- PQ.readyOutGoing outq 904 getOutGoingParam <- PQ.readyOutGoing outq