module LibP2P.Switch.Upgrade
(
performStreamHandshake
, noiseSessionToStreamIO
, yamuxToMuxerSession
, upgradeAs
, upgradeOutbound
, upgradeInbound
, readExact
, readFramedMessage
, writeFramedMessage
) where
import Control.Concurrent.Async (async, cancel, race, waitCatch)
import Control.Concurrent.STM (atomically, isEmptyTQueue, newTVarIO, retry)
import Control.Exception (SomeException, catch)
import Control.Monad (unless)
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import Data.Word (Word8)
import LibP2P.Core.Binary (readWord16BE)
import LibP2P.Crypto.Key (KeyPair (..))
import LibP2P.Crypto.PeerId (fromPublicKey)
import LibP2P.Yamux.Frame (maxStreamWindowSize)
import LibP2P.Yamux.Session (closeSession, newSession, recvLoop, sendLoop)
import qualified LibP2P.Yamux.Session as Yamux
import LibP2P.Yamux.Stream (streamRead)
import qualified LibP2P.Yamux.Stream as YS
import LibP2P.Yamux.Types (SessionRole (..), YamuxSession (ysessSendCh), YamuxStream)
import LibP2P.MultistreamSelect.Negotiation
( NegotiationResult (..)
, StreamIO (..)
, negotiateInitiator
, negotiateResponder
, readExactBounded
)
import LibP2P.Noise.Framing (chunkPlaintext, encodeFrame)
import LibP2P.Noise.Handshake
( HandshakeResult (..)
, buildHandshakePayload
, decodeNoisePayload
, encodeNoisePayload
, getRemoteNoiseStaticKey
, initHandshakeInitiator
, initHandshakeResponder
, readHandshakeMsg
, verifyStaticKey
, writeHandshakeMsg
)
import LibP2P.Noise.Session
( NoiseSession
, decryptMessage
, encryptMessage
, mkNoiseSession
)
import LibP2P.Switch.Types
( ConnState (..)
, Connection (..)
, Direction (..)
, MuxerSession (..)
)
import LibP2P.Transport
( ConnectionEndpoint (..)
, NativeMuxer (..)
, RawConnection (..)
)
import System.Timeout (timeout)
import qualified LibP2P.Crypto.Protobuf as Proto
import qualified LibP2P.Noise.Handshake as HS
readExact :: StreamIO -> Int -> IO ByteString
readExact :: StreamIO -> Int -> IO ByteString
readExact StreamIO
stream Int
n =
(String -> IO ByteString)
-> (ByteString -> IO ByteString)
-> Either String ByteString
-> IO ByteString
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> IO ByteString
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail ByteString -> IO ByteString
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
(Either String ByteString -> IO ByteString)
-> IO (Either String ByteString) -> IO ByteString
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< StreamIO -> Int -> Int -> IO (Either String ByteString)
readExactBounded StreamIO
stream (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
maxStreamWindowSize) Int
n
readFramedMessage :: StreamIO -> IO ByteString
readFramedMessage :: StreamIO -> IO ByteString
readFramedMessage StreamIO
stream = do
lenBytes <- StreamIO -> Int -> IO ByteString
readExact StreamIO
stream Int
2
let len = Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Word16
readWord16BE ByteString
lenBytes) :: Int
if len == 0
then pure BS.empty
else readExact stream len
writeFramedMessage :: StreamIO -> ByteString -> IO ()
writeFramedMessage :: StreamIO -> ByteString -> IO ()
writeFramedMessage StreamIO
stream ByteString
msg =
(String -> IO ())
-> (ByteString -> IO ()) -> Either String ByteString -> IO ()
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either String -> IO ()
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (StreamIO -> ByteString -> IO ()
streamWrite StreamIO
stream) (ByteString -> Either String ByteString
encodeFrame ByteString
msg)
performStreamHandshake
:: KeyPair -> Direction -> StreamIO -> IO (NoiseSession, HandshakeResult)
performStreamHandshake :: KeyPair
-> Direction -> StreamIO -> IO (NoiseSession, HandshakeResult)
performStreamHandshake KeyPair
identityKP Direction
dir StreamIO
stream = case Direction
dir of
Direction
Outbound -> KeyPair -> StreamIO -> IO (NoiseSession, HandshakeResult)
performInitiatorHandshake KeyPair
identityKP StreamIO
stream
Direction
Inbound -> KeyPair -> StreamIO -> IO (NoiseSession, HandshakeResult)
performResponderHandshake KeyPair
identityKP StreamIO
stream
performInitiatorHandshake :: KeyPair -> StreamIO -> IO (NoiseSession, HandshakeResult)
performInitiatorHandshake :: KeyPair -> StreamIO -> IO (NoiseSession, HandshakeResult)
performInitiatorHandshake KeyPair
identityKP StreamIO
stream = do
(hsState0, noiseStaticPub) <- KeyPair -> IO (HandshakeState, ByteString)
initHandshakeInitiator KeyPair
identityKP
(msg1, hsState1) <- either (fail . ("initiator msg1 write: " <>)) pure $
writeHandshakeMsg hsState0 BS.empty
writeFramedMessage stream msg1
msg2 <- readFramedMessage stream
(payload2, hsState2) <- either (fail . ("initiator msg2 read: " <>)) pure $
readHandshakeMsg hsState1 msg2
remoteNP <- either (fail . ("initiator decode payload: " <>)) pure $
decodeNoisePayload payload2
remotePubKey <- either (fail . ("initiator decode pubkey: " <>)) pure $
Proto.decodePublicKey (HS.npIdentityKey remoteNP)
let remotePeerId = PublicKey -> PeerId
fromPublicKey PublicKey
remotePubKey
case getRemoteNoiseStaticKey hsState2 of
Maybe ByteString
Nothing -> String -> IO ()
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"performInitiatorHandshake: remote Noise static key unavailable after msg2"
Just ByteString
remoteNoisePub ->
if Bool -> Bool
not (PublicKey -> ByteString -> ByteString -> Bool
verifyStaticKey PublicKey
remotePubKey ByteString
remoteNoisePub (NoisePayload -> ByteString
HS.npIdentitySig NoisePayload
remoteNP))
then String -> IO ()
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"performInitiatorHandshake: identity signature verification failed"
else () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
identPayload <- either (fail . ("initiator payload build: " <>)) pure $
encodeNoisePayload <$> buildHandshakePayload identityKP noiseStaticPub
(msg3, hsStateFinal) <- either (fail . ("initiator msg3 write: " <>)) pure $
writeHandshakeMsg hsState2 identPayload
writeFramedMessage stream msg3
let noiseSession = CacophonyState -> NoiseSession
mkNoiseSession (HandshakeState -> CacophonyState
HS.hsNoiseState HandshakeState
hsStateFinal)
pure (noiseSession, HandshakeResult remotePeerId remotePubKey)
performResponderHandshake :: KeyPair -> StreamIO -> IO (NoiseSession, HandshakeResult)
performResponderHandshake :: KeyPair -> StreamIO -> IO (NoiseSession, HandshakeResult)
performResponderHandshake KeyPair
identityKP StreamIO
stream = do
(hsState0, noiseStaticPub) <- KeyPair -> IO (HandshakeState, ByteString)
initHandshakeResponder KeyPair
identityKP
msg1 <- readFramedMessage stream
(_payload1, hsState1) <- either (fail . ("responder msg1 read: " <>)) pure $
readHandshakeMsg hsState0 msg1
identPayload <- either (fail . ("responder payload build: " <>)) pure $
encodeNoisePayload <$> buildHandshakePayload identityKP noiseStaticPub
(msg2, hsState2) <- either (fail . ("responder msg2 write: " <>)) pure $
writeHandshakeMsg hsState1 identPayload
writeFramedMessage stream msg2
msg3 <- readFramedMessage stream
(payload3, hsStateFinal) <- either (fail . ("responder msg3 read: " <>)) pure $
readHandshakeMsg hsState2 msg3
remoteNP <- either (fail . ("responder decode payload: " <>)) pure $
decodeNoisePayload payload3
remotePubKey <- either (fail . ("responder decode pubkey: " <>)) pure $
Proto.decodePublicKey (HS.npIdentityKey remoteNP)
let remotePeerId = PublicKey -> PeerId
fromPublicKey PublicKey
remotePubKey
case getRemoteNoiseStaticKey hsStateFinal of
Maybe ByteString
Nothing -> String -> IO ()
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"performResponderHandshake: remote Noise static key unavailable after msg3"
Just ByteString
remoteNoisePub ->
if Bool -> Bool
not (PublicKey -> ByteString -> ByteString -> Bool
verifyStaticKey PublicKey
remotePubKey ByteString
remoteNoisePub (NoisePayload -> ByteString
HS.npIdentitySig NoisePayload
remoteNP))
then String -> IO ()
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"performResponderHandshake: identity signature verification failed"
else () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
let noiseSession = CacophonyState -> NoiseSession
mkNoiseSession (HandshakeState -> CacophonyState
HS.hsNoiseState HandshakeState
hsStateFinal)
pure (noiseSession, HandshakeResult remotePeerId remotePubKey)
noiseSessionToStreamIO
:: IORef NoiseSession
-> IORef NoiseSession
-> IORef ByteString
-> StreamIO
-> StreamIO
noiseSessionToStreamIO :: IORef NoiseSession
-> IORef NoiseSession -> IORef ByteString -> StreamIO -> StreamIO
noiseSessionToStreamIO IORef NoiseSession
sendRef IORef NoiseSession
recvRef IORef ByteString
bufRef StreamIO
rawIO = StreamIO
{ streamWrite :: ByteString -> IO ()
streamWrite = IORef NoiseSession -> StreamIO -> ByteString -> IO ()
encryptAndWrite IORef NoiseSession
sendRef StreamIO
rawIO
, streamReadByte :: IO Word8
streamReadByte = IORef NoiseSession -> IORef ByteString -> StreamIO -> IO Word8
decryptAndReadByte IORef NoiseSession
recvRef IORef ByteString
bufRef StreamIO
rawIO
, streamReadChunk :: Int -> IO ByteString
streamReadChunk = IORef NoiseSession
-> IORef ByteString -> StreamIO -> Int -> IO ByteString
decryptAndReadChunk IORef NoiseSession
recvRef IORef ByteString
bufRef StreamIO
rawIO
, streamClose :: IO ()
streamClose = () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
}
encryptAndWrite :: IORef NoiseSession -> StreamIO -> ByteString -> IO ()
encryptAndWrite :: IORef NoiseSession -> StreamIO -> ByteString -> IO ()
encryptAndWrite IORef NoiseSession
sendRef StreamIO
rawIO ByteString
plaintext =
(ByteString -> IO ()) -> [ByteString] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ ByteString -> IO ()
encryptChunk (ByteString -> [ByteString]
chunkPlaintext ByteString
plaintext)
where
encryptChunk :: ByteString -> IO ()
encryptChunk ByteString
chunk = do
sess <- IORef NoiseSession -> IO NoiseSession
forall a. IORef a -> IO a
readIORef IORef NoiseSession
sendRef
case encryptMessage sess chunk of
Left String
err -> String -> IO ()
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"encryptAndWrite: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
err
Right (ByteString
ct, NoiseSession
sess') -> do
IORef NoiseSession -> NoiseSession -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef NoiseSession
sendRef NoiseSession
sess'
StreamIO -> ByteString -> IO ()
writeFramedMessage StreamIO
rawIO ByteString
ct
nextPlaintext :: IORef NoiseSession -> StreamIO -> IO ByteString
nextPlaintext :: IORef NoiseSession -> StreamIO -> IO ByteString
nextPlaintext IORef NoiseSession
recvRef StreamIO
rawIO = do
ct <- StreamIO -> IO ByteString
readFramedMessage StreamIO
rawIO
if BS.null ct
then nextPlaintext recvRef rawIO
else do
sess <- readIORef recvRef
case decryptMessage sess ct of
Left String
err -> String -> IO ByteString
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO ByteString) -> String -> IO ByteString
forall a b. (a -> b) -> a -> b
$ String
"nextPlaintext: decrypt failed: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
err
Right (ByteString
pt, NoiseSession
sess') -> do
IORef NoiseSession -> NoiseSession -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef NoiseSession
recvRef NoiseSession
sess'
if ByteString -> Bool
BS.null ByteString
pt
then IORef NoiseSession -> StreamIO -> IO ByteString
nextPlaintext IORef NoiseSession
recvRef StreamIO
rawIO
else ByteString -> IO ByteString
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ByteString
pt
decryptAndReadByte :: IORef NoiseSession -> IORef ByteString -> StreamIO -> IO Word8
decryptAndReadByte :: IORef NoiseSession -> IORef ByteString -> StreamIO -> IO Word8
decryptAndReadByte IORef NoiseSession
recvRef IORef ByteString
bufRef StreamIO
rawIO = do
buf <- IORef ByteString -> IO ByteString
forall a. IORef a -> IO a
readIORef IORef ByteString
bufRef
bs <- if BS.null buf then nextPlaintext recvRef rawIO else pure buf
writeIORef bufRef (BS.tail bs)
pure (BS.head bs)
decryptAndReadChunk :: IORef NoiseSession -> IORef ByteString -> StreamIO -> Int -> IO ByteString
decryptAndReadChunk :: IORef NoiseSession
-> IORef ByteString -> StreamIO -> Int -> IO ByteString
decryptAndReadChunk IORef NoiseSession
recvRef IORef ByteString
bufRef StreamIO
rawIO Int
n = do
buf <- IORef ByteString -> IO ByteString
forall a. IORef a -> IO a
readIORef IORef ByteString
bufRef
bs <- if BS.null buf then nextPlaintext recvRef rawIO else pure buf
let (front, rest) = BS.splitAt n bs
writeIORef bufRef rest
pure front
goAwayFlushTimeoutUs :: Int
goAwayFlushTimeoutUs :: Int
goAwayFlushTimeoutUs = Int
200000
yamuxToMuxerSession :: YamuxSession -> IO () -> IO MuxerSession
yamuxToMuxerSession :: YamuxSession -> IO () -> IO MuxerSession
yamuxToMuxerSession YamuxSession
yamuxSess IO ()
closeTransport = do
sendLoopA <- IO () -> IO (Async ())
forall a. IO a -> IO (Async a)
async (YamuxSession -> IO ()
sendLoop YamuxSession
yamuxSess)
recvLoopA <- async (recvLoop yamuxSess)
pure MuxerSession
{ muxOpenStream = do
result <- Yamux.openStream yamuxSess
case result of
Right YamuxStream
stream -> YamuxStream -> IO StreamIO
yamuxStreamToStreamIO YamuxStream
stream
Left YamuxError
err -> String -> IO StreamIO
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO StreamIO) -> String -> IO StreamIO
forall a b. (a -> b) -> a -> b
$ String
"muxOpenStream: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> YamuxError -> String
forall a. Show a => a -> String
show YamuxError
err
, muxAcceptStream = do
result <- race (waitCatch recvLoopA) (Yamux.acceptStream yamuxSess)
case result of
Left Either SomeException ()
_ -> String -> IO StreamIO
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"muxAcceptStream: session terminated"
Right (Right YamuxStream
stream) -> YamuxStream -> IO StreamIO
yamuxStreamToStreamIO YamuxStream
stream
Right (Left YamuxError
err) -> String -> IO StreamIO
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO StreamIO) -> String -> IO StreamIO
forall a b. (a -> b) -> a -> b
$ String
"muxAcceptStream: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> YamuxError -> String
forall a. Show a => a -> String
show YamuxError
err
, muxClose = do
closeSession yamuxSess
_ <- timeout goAwayFlushTimeoutUs $ atomically $ do
empty <- isEmptyTQueue (ysessSendCh yamuxSess)
unless empty retry
cancel sendLoopA
cancel recvLoopA
closeTransport `catch` \(SomeException
_ :: SomeException) -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
}
yamuxStreamToStreamIO :: YamuxStream -> IO StreamIO
yamuxStreamToStreamIO :: YamuxStream -> IO StreamIO
yamuxStreamToStreamIO YamuxStream
yamuxStream = do
readBuf <- ByteString -> IO (IORef ByteString)
forall a. a -> IO (IORef a)
newIORef ByteString
BS.empty
let
nextChunk = do
buf <- IORef ByteString -> IO ByteString
forall a. IORef a -> IO a
readIORef IORef ByteString
readBuf
if BS.null buf
then do
result <- streamRead yamuxStream
case result of
Left YamuxError
err -> String -> IO ByteString
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO ByteString) -> String -> IO ByteString
forall a b. (a -> b) -> a -> b
$ String
"yamuxStreamRead: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> YamuxError -> String
forall a. Show a => a -> String
show YamuxError
err
Right ByteString
chunk
| ByteString -> Bool
BS.null ByteString
chunk -> String -> IO ByteString
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"yamuxStreamRead: empty chunk"
| Bool
otherwise -> ByteString -> IO ByteString
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ByteString
chunk
else pure buf
pure StreamIO
{ streamWrite = \ByteString
bs -> do
result <- YamuxStream -> ByteString -> IO (Either YamuxError ())
YS.streamWrite YamuxStream
yamuxStream ByteString
bs
case result of
Right () -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Left YamuxError
err -> String -> IO ()
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"yamuxStreamWrite: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> YamuxError -> String
forall a. Show a => a -> String
show YamuxError
err
, streamReadByte = do
chunk <- nextChunk
writeIORef readBuf (BS.tail chunk)
pure (BS.head chunk)
, streamReadChunk = \Int
n -> do
chunk <- IO ByteString
nextChunk
let (front, rest) = BS.splitAt n chunk
writeIORef readBuf rest
pure front
, streamClose = do
_ <- YS.streamClose yamuxStream
pure ()
}
upgradeAs :: Direction -> KeyPair -> RawConnection -> IO Connection
upgradeAs :: Direction -> KeyPair -> RawConnection -> IO Connection
upgradeAs Direction
dir KeyPair
identityKP RawConnection
rawConn = case RawConnection -> ConnectionEndpoint
rcEndpoint RawConnection
rawConn of
ByteStreamEndpoint StreamIO
rawIO -> Direction -> KeyPair -> RawConnection -> StreamIO -> IO Connection
upgradeByteStream Direction
dir KeyPair
identityKP RawConnection
rawConn StreamIO
rawIO
NativeMuxerEndpoint NativeMuxer
native -> Direction -> RawConnection -> NativeMuxer -> IO Connection
nativeToConnection Direction
dir RawConnection
rawConn NativeMuxer
native
upgradeByteStream :: Direction -> KeyPair -> RawConnection -> StreamIO -> IO Connection
upgradeByteStream :: Direction -> KeyPair -> RawConnection -> StreamIO -> IO Connection
upgradeByteStream Direction
dir KeyPair
identityKP RawConnection
rawConn StreamIO
rawIO = do
let isServer :: Bool
isServer = Direction
dir Direction -> Direction -> Bool
forall a. Eq a => a -> a -> Bool
== Direction
Inbound
negotiate :: StreamIO -> [ProtocolId] -> IO NegotiationResult
negotiate = if Bool
isServer then StreamIO -> [ProtocolId] -> IO NegotiationResult
negotiateResponder else StreamIO -> [ProtocolId] -> IO NegotiationResult
negotiateInitiator
role :: String
role = if Bool
isServer then String
"upgradeInbound" else String
"upgradeOutbound"
secResult <- StreamIO -> [ProtocolId] -> IO NegotiationResult
negotiate StreamIO
rawIO [ProtocolId
"/noise"]
case secResult of
Accepted ProtocolId
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
NegotiationResult
NoProtocol -> String -> IO ()
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String
role String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
": /noise negotiation failed")
(noiseSess, HandshakeResult remotePeerId _remotePK) <-
performStreamHandshake identityKP dir rawIO
sendRef <- newIORef noiseSess
recvRef <- newIORef noiseSess
bufRef <- newIORef BS.empty
let encryptedIO = IORef NoiseSession
-> IORef NoiseSession -> IORef ByteString -> StreamIO -> StreamIO
noiseSessionToStreamIO IORef NoiseSession
sendRef IORef NoiseSession
recvRef IORef ByteString
bufRef StreamIO
rawIO
muxResult <- negotiate encryptedIO ["/yamux/1.0.0"]
case muxResult of
Accepted ProtocolId
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
NegotiationResult
NoProtocol -> String -> IO ()
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String
role String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
": /yamux/1.0.0 negotiation failed")
let yamuxWrite = StreamIO -> ByteString -> IO ()
streamWrite StreamIO
encryptedIO
yamuxRead = \Int
n -> StreamIO -> Int -> IO ByteString
readExact StreamIO
encryptedIO Int
n
yamuxSess <- newSession (if isServer then RoleServer else RoleClient) yamuxWrite yamuxRead
muxer <- yamuxToMuxerSession yamuxSess (rcClose rawConn)
stateVar <- newTVarIO ConnOpen
pure Connection
{ connPeerId = remotePeerId
, connDirection = dir
, connLocalAddr = rcLocalAddr rawConn
, connRemoteAddr = rcRemoteAddr rawConn
, connSecurity = "/noise"
, connMuxer = "/yamux/1.0.0"
, connSession = muxer
, connState = stateVar
}
nativeToConnection :: Direction -> RawConnection -> NativeMuxer -> IO Connection
nativeToConnection :: Direction -> RawConnection -> NativeMuxer -> IO Connection
nativeToConnection Direction
dir RawConnection
rawConn NativeMuxer
native = do
stateVar <- ConnState -> IO (TVar ConnState)
forall a. a -> IO (TVar a)
newTVarIO ConnState
ConnOpen
let muxer = MuxerSession
{ muxOpenStream :: IO StreamIO
muxOpenStream = NativeMuxer -> IO StreamIO
nativeOpenStream NativeMuxer
native
, muxAcceptStream :: IO StreamIO
muxAcceptStream = NativeMuxer -> IO StreamIO
nativeAcceptStream NativeMuxer
native
, muxClose :: IO ()
muxClose = NativeMuxer -> IO ()
nativeClose NativeMuxer
native
}
pure Connection
{ connPeerId = nativePeerId native
, connDirection = dir
, connLocalAddr = rcLocalAddr rawConn
, connRemoteAddr = rcRemoteAddr rawConn
, connSecurity = nativeSecurity native
, connMuxer = nativeMuxerProtocol native
, connSession = muxer
, connState = stateVar
}
upgradeOutbound :: KeyPair -> RawConnection -> IO Connection
upgradeOutbound :: KeyPair -> RawConnection -> IO Connection
upgradeOutbound = Direction -> KeyPair -> RawConnection -> IO Connection
upgradeAs Direction
Outbound
upgradeInbound :: KeyPair -> RawConnection -> IO Connection
upgradeInbound :: KeyPair -> RawConnection -> IO Connection
upgradeInbound = Direction -> KeyPair -> RawConnection -> IO Connection
upgradeAs Direction
Inbound