libp2p-hs-0.1.0.0: Haskell implementation of the libp2p networking stack
Safe HaskellNone
LanguageGHC2021

LibP2P.MultistreamSelect.Negotiation

Description

multistream-select protocol negotiation.

Implements Initiator and Responder roles for negotiating which protocol to use over a connection or stream.

Synopsis

Documentation

type ProtocolId = Text Source #

A protocol identifier (e.g. "noise", "yamux/1.0.0").

data StreamIO Source #

Abstraction for stream I/O to enable testing with in-memory buffers.

Constructors

StreamIO 

Fields

  • streamWrite :: ByteString -> IO ()
     
  • streamReadByte :: IO Word8

    Read exactly one byte (blocks until available)

  • streamReadChunk :: Int -> IO ByteString

    Read between 1 and n bytes (n >= 1): whatever is already buffered or arrives next, without waiting for the full n. Blocks until at least one byte is available and never returns an empty ByteString; EOF and failures surface as IOException, exactly like streamReadByte. Bulk readers use this to move data at chunk granularity instead of byte-at-a-time (#276).

  • streamClose :: IO ()

    Close/half-close the stream (signals EOF to remote)

negotiateInitiator :: StreamIO -> [ProtocolId] -> IO NegotiationResult Source #

Negotiate as the Initiator.

Pipelines the multistream header and the first protocol proposal in a single write before reading anything, as the multistream-select spec recommends ("the initiator SHOULD pipeline the multistream protocol id and the desired protocol id in the same packet"): this saves one round trip per negotiation. It then reads the header echo and the reply to the optimistic proposal; on na it falls back to proposing the remaining protocols sequentially.

negotiateResponder :: StreamIO -> [ProtocolId] -> IO NegotiationResult Source #

Negotiate as the Responder. Receives header, then responds to the initiator's proposal.

mkByteStreamIO :: (ByteString -> IO ()) -> IO Word8 -> IO () -> StreamIO Source #

Build a StreamIO from byte-level primitives: streamReadChunk falls back to one byte per call. Correct for any consumer (chunk reads promise at least one byte, not n), just not fast — intended for tests and mocks built on byte queues.

mkMemoryStreamPair :: IO (StreamIO, StreamIO) Source #

Create an in-memory stream pair for testing using STM TQueue. Writes to stream A appear as reads on stream B and vice versa.

readExactBounded Source #

Arguments

:: StreamIO 
-> Int

Maximum acceptable length (protocol-defined cap)

-> Int

Number of bytes to read

-> IO (Either String ByteString) 

Read exactly n bytes from a stream, bounded by maxLen.

Shared by every length-delimited protocol in the stack (see issue #169): the declared length is validated against the caller's protocol-defined cap before a single byte is read or allocated, so a hostile length prefix cannot trigger an unbounded allocation. Bytes are read via streamReadChunk in requests of at most readChunkSize, keeping transient memory use proportional to the chunk size, not to n. A chunk request never exceeds the bytes still owed, so no byte beyond n is consumed from the stream.

I/O failures during the read (stream reset, EOF) are returned as Left instead of propagating as IOExceptions.

closeQuietly :: StreamIO -> IO () Source #

Close a stream, swallowing any exception (best-effort EOF signal). Shared by protocol handlers that must release a stream on every exit path without letting a close-time error mask the real outcome.