libp2p.transport.webrtc package
Subpackages
Submodules
libp2p.transport.webrtc.certificate module
WebRTC certificate utilities.
Generates ECDSA P-256 self-signed certificates for WebRTC DTLS and computes
SHA-256 fingerprints encoded as multihash/multibase for embedding in
/webrtc-direct/certhash/<encoded> multiaddrs.
Spec: https://github.com/libp2p/specs/blob/master/webrtc/webrtc-direct.md
- class libp2p.transport.webrtc.certificate.WebRTCCertificate(certificate: Certificate, private_key: EllipticCurvePrivateKey)
Bases:
objectHolds an ECDSA P-256 certificate and its SHA-256 fingerprint for WebRTC.
Use
generate()to create a fresh self-signed certificate, orfrom_existing()to wrap an already-created certificate/key pair.- fingerprint_to_multibase() str
Encode the fingerprint as a multibase base64url string.
The result can be used directly as the
certhashcomponent in a/webrtc-directmultiaddr.Format:
uprefix + base64url(multihash(sha256(DER cert)))
- fingerprint_to_multihash() bytes
Encode the fingerprint as a multihash (varint code + varint length + digest).
For SHA-256 both code (0x12) and length (32) fit in a single byte, so we avoid a full varint encoder.
- classmethod from_aiortc() WebRTCCertificate
Generate a certificate using aiortc’s
RTCCertificate.Preferred when aiortc is installed because it avoids any cryptography ↔ pyOpenSSL conversion — aiortc’s internal cert is already a
cryptography.x509.Certificate.- Returns:
A new
WebRTCCertificatebacked by an aiortc cert.- Raises:
ImportError – If aiortc is not installed.
WebRTCCertificateError – If certificate generation fails.
- classmethod generate(common_name: str = 'libp2p-webrtc', validity_days: int = 14) WebRTCCertificate
Generate a fresh ECDSA P-256 self-signed certificate.
The spec requires ECDSA with the P-256 curve for browser compatibility.
- Parameters:
common_name – Certificate subject CN.
validity_days – How long the certificate is valid.
- Returns:
A new
WebRTCCertificate.- Raises:
WebRTCCertificateError – If certificate generation fails.
- libp2p.transport.webrtc.certificate.fingerprint_from_multibase(encoded: str) bytes
Decode a multibase-encoded certhash back to raw SHA-256 fingerprint bytes.
- Parameters:
encoded – Multibase string (e.g.
uEi...).- Returns:
32-byte SHA-256 digest.
- Raises:
WebRTCCertificateError – If the encoding is invalid.
libp2p.transport.webrtc.config module
WebRTC transport configuration.
- class libp2p.transport.webrtc.config.WebRTCTransportConfig(certificate: ~libp2p.transport.webrtc.certificate.WebRTCCertificate | None = None, ice_disconnection_timeout: float = 20.0, ice_failure_timeout: float = 30.0, ice_keepalive_interval: float = 15.0, handshake_timeout: float = 30.0, stream_open_timeout: float = 10.0, stream_accept_timeout: float = 10.0, max_in_flight_connections: int = 128, accept_queue_size: int = 256, max_concurrent_streams: int = 256, max_message_size: int = 16384, ice_servers: list[str] = <factory>)
Bases:
objectConfiguration for the WebRTC transport.
Sensible defaults match go-libp2p. Override for testing or constrained environments.
- certificate: WebRTCCertificate | None = None
- get_or_generate_certificate() WebRTCCertificate
Return the configured certificate or generate a new one.
Prefers aiortc-native generation when available so the resulting
RTCCertificatecan be passed directly toRTCPeerConnection(certificates=[...]). Falls back to purecryptographygeneration when aiortc is not installed.
libp2p.transport.webrtc.connection module
WebRTC connection — dual IRawConnection + IMuxedConn interface.
Follows the same pattern as QUICConnection: WebRTC provides native
stream multiplexing via data channels, so the connection implements both
the raw transport and the muxer interface. The swarm skips the
TransportUpgrader for native-muxing transports.
Each outbound stream gets an even data-channel ID starting at 2. Each inbound stream gets an odd data-channel ID starting at 1. Channel 0 is reserved for the Noise handshake.
Spec: https://github.com/libp2p/specs/blob/master/webrtc/webrtc.md
- class libp2p.transport.webrtc.connection.WebRTCConnection(peer_id: ID, bridge: AsyncioBridge, is_initiator: bool, config: WebRTCTransportConfig | None = None, remote_addrs: list[Multiaddr] | None = None)
Bases:
IRawConnection,IMuxedConnA WebRTC peer connection providing native stream multiplexing.
Wraps an aiortc
RTCPeerConnection(viaAsyncioBridge) and maps each data channel to aWebRTCStream.This class does NOT import or call aiortc directly. All aiortc interaction happens through the bridge and the
_send_on_channel/_create_channel/_close_pccallbacks set by the transport. This keeps the connection testable without aiortc installed.- async accept_stream() IMuxedStream
Accept an inbound stream (waits for a remote data channel).
- Returns:
A
WebRTCStream.- Raises:
WebRTCStreamError – If the connection is closed.
- get_connection_type() ConnectionType
Get the type of connection (direct, relayed, etc.)
- get_remote_address() tuple[str, int] | None
Return the remote address of the connected peer.
- Returns:
A tuple of (host, port) or None if not available
- get_transport_addresses() list[Multiaddr]
Get the actual transport addresses used by this connection.
Returns the real IP/port addresses, not peerstore addresses. For relayed connections, should include /p2p-circuit in the path.
- property is_closed: bool
Check if the connection is fully closed.
- Returns:
True if the connection is closed, otherwise False.
- property is_established: bool
Check if the connection is fully established and ready for streams.
- Returns:
True if the connection is established, otherwise False.
- property is_initiator: bool
Determine if this connection is the initiator.
- Returns:
True if this connection initiated the connection, otherwise False.
- on_channel_message(channel_id: int, data: bytes) None
Route a received data-channel message to the correct stream.
Stream-level routing is done on whatever thread we’re called from; the stream itself (
WebRTCStream.on_data()) handles the foreign-thread hand-off to Trio.
- on_datachannel(channel_id: int) WebRTCStream
Register an inbound data channel as a new stream.
Called by the transport layer when a remote peer creates a data channel. May be invoked from the asyncio bridge thread; any Trio-side enqueueing is routed through
_run_on_trio_thread().- Parameters:
channel_id – The data channel ID.
- Returns:
The created
WebRTCStream.
- async open_stream() IMuxedStream
Open a new outbound stream (creates a WebRTC data channel).
- Returns:
A
WebRTCStreamready for reading/writing.- Raises:
WebRTCStreamError – If the connection is closed or stream limit is reached.
libp2p.transport.webrtc.constants module
WebRTC transport constants.
Protocol codes, message size limits, and data-channel ID allocation rules per the libp2p WebRTC specification.
libp2p.transport.webrtc.exceptions module
WebRTC transport exception hierarchy.
WebRTCConnectionError also subclasses OpenConnectionError so that
generic transport error handling in the swarm layer catches WebRTC dial
failures the same way it catches TCP/QUIC failures.
- exception libp2p.transport.webrtc.exceptions.WebRTCCertificateError
Bases:
WebRTCErrorCertificate generation, parsing, or fingerprint errors.
- exception libp2p.transport.webrtc.exceptions.WebRTCConnectionError
Bases:
WebRTCError,OpenConnectionErrorICE negotiation, DTLS, or peer connection failure.
- exception libp2p.transport.webrtc.exceptions.WebRTCError
Bases:
BaseLibp2pErrorBase exception for all WebRTC transport errors.
- exception libp2p.transport.webrtc.exceptions.WebRTCHandshakeError
Bases:
WebRTCErrorNoise handshake failure over data-channel 0.
- exception libp2p.transport.webrtc.exceptions.WebRTCMultiaddrError
Bases:
WebRTCErrorInvalid or unparseable WebRTC multiaddr.
- exception libp2p.transport.webrtc.exceptions.WebRTCSignalingError
Bases:
WebRTCErrorSDP/ICE signaling exchange failure (private-to-private mode).
- exception libp2p.transport.webrtc.exceptions.WebRTCStreamError
Bases:
WebRTCErrorData-channel stream read/write or lifecycle error.
libp2p.transport.webrtc.listener module
WebRTC Direct listener.
Runs a lightweight HTTP signaling server on TCP (same port number as the
WebRTC UDP endpoint) that accepts SDP offers and returns answers. After
the SDP exchange each incoming connection completes ICE/DTLS, a Noise XX
handshake over data-channel 0, and then hands the fully-authenticated
WebRTCConnection to the registered handler.
Published multiaddr format:
/ip4/<bound-ip>/udp/<bound-port>/webrtc-direct/certhash/<hash>/p2p/<peer-id>
Spec: https://github.com/libp2p/specs/blob/master/webrtc/webrtc-direct.md
- class libp2p.transport.webrtc.listener.WebRTCDirectListener(handler_function: Callable[[ReadWriteCloser], Awaitable[None]], private_key: PrivateKey, certificate: WebRTCCertificate, config: WebRTCTransportConfig, bridge_factory: Callable[[], Awaitable[Any]], local_peer_id: ID)
Bases:
IListenerListens for incoming WebRTC Direct connections.
Created by
WebRTCDirectTransport.create_listener().- async listen(maddr: Multiaddr) None
Start listening for incoming WebRTC Direct connections.
Starts an HTTP signaling server on TCP that accepts SDP offers. The published multiaddr advertises the same port on UDP (for WebRTC data channels) and includes the DTLS certificate hash.
- Parameters:
maddr – A
/webrtc-directmultiaddr.- Raises:
WebRTCConnectionError – If binding fails.
libp2p.transport.webrtc.multiaddr_utils module
WebRTC multiaddr utilities.
Parse and construct /webrtc-direct and /webrtc multiaddrs.
WebRTC Direct format:
/ip4/<ip>/udp/<port>/webrtc-direct/certhash/<multibase-multihash>/p2p/<peer-id>
WebRTC (relay-based) format:
<relay-multiaddr>/p2p-circuit/webrtc/p2p/<peer-id>
Spec: https://github.com/libp2p/specs/blob/master/webrtc/webrtc-direct.md
- libp2p.transport.webrtc.multiaddr_utils.build_webrtc_direct_multiaddr(host: str, port: int, certhash_multibase: str, peer_id: str | None = None) Multiaddr
Construct a
/webrtc-directmultiaddr.- Parameters:
host – IPv4 or IPv6 address string.
port – UDP port number.
certhash_multibase – Multibase-encoded certificate hash (e.g.
uEi...).peer_id – Optional base58 peer ID.
- Returns:
A
Multiaddr.- Raises:
WebRTCMultiaddrError – If inputs are invalid.
- libp2p.transport.webrtc.multiaddr_utils.is_webrtc_direct_multiaddr(maddr: Multiaddr) bool
Check whether maddr is a valid WebRTC Direct address.
- Parameters:
maddr – Multiaddr to test.
- Returns:
True if the address contains
/webrtc-direct.
- libp2p.transport.webrtc.multiaddr_utils.is_webrtc_multiaddr(maddr: Multiaddr) bool
Check whether maddr is a relay-based WebRTC address.
A valid address contains
/p2p-circuit/webrtc/.
- libp2p.transport.webrtc.multiaddr_utils.parse_webrtc_direct_multiaddr(maddr: Multiaddr) tuple[str, int, str | None, str | None]
Extract components from a
/webrtc-directmultiaddr.- Parameters:
maddr – A WebRTC Direct multiaddr.
- Returns:
Tuple of
(host, port, certhash_multibase, peer_id_str), where the last two may beNoneif absent in the multiaddr.- Raises:
WebRTCMultiaddrError – If the multiaddr is malformed.
libp2p.transport.webrtc.noise_handshake module
Noise XX handshake over WebRTC data channel 0.
Per the libp2p WebRTC spec, after a DTLS connection is established the two peers perform a Noise XX handshake over data channel 0 to mutually authenticate. The Noise prologue binds the handshake to the DTLS session by incorporating both peers’ certificate fingerprints.
Prologue format:
b"libp2p-webrtc-noise:" + encode(local_fp) + encode(remote_fp)
Where encode(fp) is the multihash-encoded SHA-256 fingerprint of the
peer’s DTLS certificate.
Spec: https://github.com/libp2p/specs/blob/master/webrtc/webrtc.md#noise-handshake
- class libp2p.transport.webrtc.noise_handshake.DataChannelReadWriter(send_cb: Callable[[bytes], Awaitable[None]], recv_cb: Callable[[], Awaitable[bytes]], is_initiator: bool)
Bases:
IRawConnectionWraps a WebRTC data channel (stream) as an
IRawConnectionso the existing Noise handshake code (PatternXX) can read/write over it without modification.The data channel is represented by
send_cbandrecv_cbcallables rather than a direct aiortc reference.- get_connection_type() ConnectionType
Get the type of connection (direct, relayed, etc.)
- get_remote_address() tuple[str, int] | None
Return the remote address of the connected peer.
- Returns:
A tuple of (host, port) or None if not available
- libp2p.transport.webrtc.noise_handshake.build_noise_prologue(local_fingerprint: bytes, remote_fingerprint: bytes) bytes
Build the Noise prologue that binds the handshake to the DTLS session.
- Parameters:
local_fingerprint – Raw SHA-256 of the local DTLS certificate.
remote_fingerprint – Raw SHA-256 of the remote DTLS certificate.
- Returns:
The prologue bytes for
NoiseState.set_prologue().
- async libp2p.transport.webrtc.noise_handshake.perform_noise_handshake(conn: IRawConnection, local_peer: ID, libp2p_privkey: PrivateKey, noise_static_key: PrivateKey, local_fingerprint: bytes, remote_fingerprint: bytes, is_initiator: bool, remote_peer: ID | None = None) ID
Run the Noise XX handshake over a data-channel-0 connection.
- Parameters:
conn – A
IRawConnectionwrapping data channel 0.local_peer – The local peer’s ID.
libp2p_privkey – The local peer’s libp2p identity private key.
noise_static_key – An ephemeral X25519 key for the Noise session.
local_fingerprint – Raw SHA-256 of the local DTLS certificate.
remote_fingerprint – Raw SHA-256 of the remote DTLS certificate.
is_initiator – True if this peer initiated the connection.
remote_peer – Expected remote peer ID (for outbound connections).
- Returns:
The authenticated remote peer ID.
- Raises:
WebRTCHandshakeError – If the handshake fails.
libp2p.transport.webrtc.private_listener module
WebRTC private-to-private listener.
Registers as a stream handler for /webrtc-signaling/0.0.1 on the
local host. When a remote peer sends a signaling stream through a relay,
this listener handles the SDP exchange, establishes a direct WebRTC
connection, and calls the handler function.
The listener advertises multiaddrs of the form:
<relay-multiaddr>/p2p-circuit/webrtc/p2p/<local-peer-id>
Spec: https://github.com/libp2p/specs/blob/master/webrtc/webrtc.md
- class libp2p.transport.webrtc.private_listener.WebRTCPrivateListener(handler_function: Callable[[ReadWriteCloser], Awaitable[None]], private_key: PrivateKey, certificate: WebRTCCertificate, config: WebRTCTransportConfig, bridge_factory: Callable[[], Awaitable[Any]], local_peer_id: ID, host: object | None = None)
Bases:
IListenerListens for incoming WebRTC signaling over Circuit Relay v2.
Created by
WebRTCPrivateTransport.create_listener().
libp2p.transport.webrtc.private_transport module
WebRTC private-to-private transport.
Implements ITransport for the /webrtc multiaddr scheme where
both peers are behind NAT. Uses Circuit Relay v2 for the signaling channel,
then upgrades to a direct WebRTC data-channel connection.
Multiaddr format:
<relay-multiaddr>/p2p-circuit/webrtc/p2p/<remote-peer-id>
The dial sequence:
Open a relayed connection to the remote peer.
Open a stream with
/webrtc-signaling/0.0.1.Exchange SDP offer/answer via
SignalingSession.Trickle ICE candidates with bilateral
ICE_DONE(specs#585 fix).Wait for direct WebRTC connection to establish.
Perform Noise XX handshake over data channel 0.
Return
WebRTCConnection.
Spec: https://github.com/libp2p/specs/blob/master/webrtc/webrtc.md
- class libp2p.transport.webrtc.private_transport.WebRTCPrivateTransport(private_key: PrivateKey, host: object | None = None, config: WebRTCTransportConfig | None = None)
Bases:
ITransportWebRTC transport for private-to-private connections (
/webrtc).Both peers are behind NAT. Signaling happens over a Circuit Relay v2 stream, then a direct WebRTC connection is established.
Usage:
transport = WebRTCPrivateTransport(private_key=my_key, host=my_host) conn = await transport.dial( Multiaddr("/ip4/.../udp/.../quic-v1/p2p/<relay>/p2p-circuit/webrtc/p2p/<remote>") )
- can_dial(maddr: Multiaddr) bool
Return True if this transport can dial the given multiaddr.
The TransportManager calls this method before attempting a dial to route the connection to the correct transport.
Parameters
- maddrMultiaddr
The multiaddress to check.
Returns
- bool
True if this transport can dial maddr, False otherwise.
Examples
TCP returns True for
/ip4/127.0.0.1/tcp/4001WebSocket returns True for
/ip4/127.0.0.1/tcp/8080/wsQUIC returns True for
/ip4/127.0.0.1/udp/4001/quic-v1
- can_listen(maddr: Multiaddr) bool
Return True if this transport can listen on the given multiaddr.
Often identical to
can_dial()but may differ — e.g. a relay transport can dial outbound but cannot accept inbound connections.Parameters
- maddrMultiaddr
The multiaddress to check.
Returns
- bool
True if this transport can listen on maddr, False otherwise.
- async close() None
Shut down the transport and its asyncio bridge.
Acquires the same lock as
_ensure_bridge()so a concurrent dial cannot resurrect the bridge mid-shutdown.
- create_listener(handler_function: Callable[[ReadWriteCloser], Awaitable[None]]) WebRTCPrivateListener
Create a listener for incoming WebRTC signaling.
The listener registers a stream handler for
/webrtc-signaling/0.0.1on the host so that remote peers can initiate WebRTC connections through a relay.- Parameters:
handler_function – Called with each new inbound connection.
- Returns:
A
WebRTCPrivateListener.
- async dial(maddr: Multiaddr) WebRTCConnection
Dial a remote peer over WebRTC via a relay.
- Parameters:
maddr – A
/p2p-circuit/webrtc/p2p/<peer-id>multiaddr.- Returns:
A
WebRTCConnection.- Raises:
NotImplementedError – The aiortc / signaling integration is not yet wired up. Returning a bare
WebRTCConnectionhere would make the swarm treat the peer as connected while streams silently drop data. The full sequence (relay dial, SDP/ICE signaling with bilateral ICE_DONE, Noise handshake) lands in a follow-up PR.WebRTCConnectionError – If the multiaddr is malformed.
- protocols() list[str]
Return the list of multiaddr protocol names this transport handles.
Used by
TransportManageras a fast pre-filter: if the multiaddr contains none of the listed protocol names,can_dial/can_listenare not called.Returns
- list[str]
Protocol name strings, e.g.
["tcp"],["ws", "wss"], or["quic", "quic-v1"].
libp2p.transport.webrtc.sdp module
SDP construction for WebRTC Direct.
For WebRTC Direct, there is no signaling exchange — the client constructs an SDP offer locally from the server’s multiaddr (IP, port, certificate hash). The server answers with its own locally-constructed SDP.
All ICE credential injection is isolated in SDPBuilder._apply_ice_credentials()
so that when Chrome removes ICE credential munging (libp2p/specs#672) only
that single method needs to change.
Spec: https://github.com/libp2p/specs/blob/master/webrtc/webrtc-direct.md
- class libp2p.transport.webrtc.sdp.SDPBuilder(certificate: WebRTCCertificate, max_message_size: int = 16384)
Bases:
objectBuilds SDP offer/answer for WebRTC Direct connections.
Usage:
builder = SDPBuilder(certificate=my_cert) offer_sdp = builder.build_offer(host="127.0.0.1", port=9090) answer_sdp = builder.build_answer( host="127.0.0.1", port=9090, remote_ufrag="...", remote_pwd="..." )
- build_answer(host: str, port: int, remote_ufrag: str, remote_pwd: str) tuple[str, str, str]
Build an SDP answer in response to a remote offer.
Per RFC 8445 §5.2, the answer includes its own fresh ufrag/pwd for connectivity checks. The remote credentials are passed through to
_apply_ice_credentialsfor the ICE agent to use during connectivity checks (needed when specs#672 changes the credential injection mechanism).- Parameters:
host – Local listening IP address.
port – Local listening UDP port.
remote_ufrag – ICE ufrag from the remote offer.
remote_pwd – ICE pwd from the remote offer.
- Returns:
Tuple of
(sdp_string, local_ice_ufrag, local_ice_pwd).
- build_offer(host: str, port: int) tuple[str, str, str]
Build an SDP offer for initiating a WebRTC Direct connection.
- Parameters:
host – Remote server IP address.
port – Remote server UDP port.
- Returns:
Tuple of
(sdp_string, ice_ufrag, ice_pwd).
- static build_sdp_from_multiaddr(host: str, port: int, certhash_multibase: str) str
Build a server-side SDP from multiaddr components for WebRTC Direct.
For WebRTC Direct the client knows the server’s cert hash from the multiaddr. This constructs the SDP that the server would advertise.
- Parameters:
host – Server IP address.
port – Server UDP port.
certhash_multibase – Multibase-encoded certificate fingerprint.
- Returns:
SDP string.
- libp2p.transport.webrtc.sdp.fingerprint_from_sdp(sdp: str) bytes
Extract the DTLS certificate fingerprint from an SDP string.
Looks for the
a=fingerprint:sha-256line and parses the colon-separated hex digest.- Parameters:
sdp – SDP string.
- Returns:
Raw SHA-256 fingerprint bytes (32 bytes).
- Raises:
WebRTCConnectionError – If no valid fingerprint line found.
libp2p.transport.webrtc.signaling module
WebRTC signaling protocol for private-to-private connections.
Implements /webrtc-signaling/0.0.1 — the protocol used to exchange SDP
offers/answers and ICE candidates over a Circuit Relay v2 stream so that
two NATed peers can establish a direct WebRTC data-channel connection.
The bilateral ICE_DONE mechanism (libp2p/specs#585 fix) ensures that
neither side closes the signaling stream before the other has received all
ICE candidates:
Initiator Responder (via relay)
──── SDP_OFFER ─────────────────────────>
<─── SDP_ANSWER ─────────────────────────
<──> ICE_CANDIDATE (trickle, both ways) <>
──── ICE_DONE ───────────────────────────>
<─── ICE_DONE ───────────────────────────
(both sides close signaling stream)
Messages are varint-length-prefixed protobuf SignalingMessage.
Spec: https://github.com/libp2p/specs/blob/master/webrtc/webrtc.md
- class libp2p.transport.webrtc.signaling.SignalingSession(stream: INetStream, timeout: float = 30.0)
Bases:
objectManages a signaling exchange between two peers.
Handles the ordered message flow: SDP_OFFER → SDP_ANSWER → ICE candidates (trickle) → bilateral ICE_DONE.
Usage (initiator side):
session = SignalingSession(stream) await session.send_offer(sdp_offer_bytes) answer_bytes = await session.receive_answer() async for candidate in session.receive_candidates(): # apply candidate to RTCPeerConnection pass await session.send_candidates(my_candidates) await session.complete() # bilateral ICE_DONE
Usage (responder side):
session = SignalingSession(stream) offer_bytes = await session.receive_offer() await session.send_answer(sdp_answer_bytes) async for candidate in session.receive_candidates(): pass await session.send_candidates(my_candidates) await session.complete()
- async complete() None
Complete the signaling exchange.
Ensures both sides have sent AND received ICE_DONE before closing the stream. This prevents the race condition in specs#585 where one side closes the stream before the other has received all candidates.
- async receive_candidates() AsyncIterator[bytes]
Yield ICE candidates from the remote peer until ICE_DONE is received.
This is an async generator — iterate it to get candidates as they arrive. The generator completes when the remote sends ICE_DONE.
- async libp2p.transport.webrtc.signaling.read_signaling_message(stream: INetStream) SignalingMessage
Read a varint-length-prefixed signaling message from the stream.
- Parameters:
stream – The relay stream.
- Returns:
The parsed protobuf message.
- Raises:
WebRTCSignalingError – If reading or parsing fails.
- async libp2p.transport.webrtc.signaling.write_signaling_message(stream: INetStream, msg: SignalingMessage) None
Write a varint-length-prefixed signaling message to the stream.
- Parameters:
stream – The relay stream.
msg – The protobuf message to send.
- Raises:
WebRTCSignalingError – If writing fails.
libp2p.transport.webrtc.stream module
WebRTC data-channel stream.
Each libp2p stream maps to one WebRTC data channel. Every write is wrapped
in a protobuf Message with an optional Flag for lifecycle
signaling. The FIN/FIN_ACK/STOP_SENDING/RESET state machine follows the
libp2p WebRTC specification exactly.
Spec: https://github.com/libp2p/specs/blob/master/webrtc/webrtc.md
- class libp2p.transport.webrtc.stream.StreamState(value)
Bases:
EnumData-channel stream lifecycle states.
- CLOSED = 'closed'
- OPEN = 'open'
- READ_CLOSED = 'read_closed'
- RESET = 'reset'
- WRITE_CLOSED = 'write_closed'
- class libp2p.transport.webrtc.stream.WebRTCStream(connection: WebRTCConnection, channel_id: int, is_initiator: bool, trio_token: trio.lowlevel.TrioToken | None = None)
Bases:
IMuxedStreamA single multiplexed stream over a WebRTC data channel.
Implements
IMuxedStreamwith protobuf framing and the FIN/FIN_ACK lifecycle protocol from the spec.The stream does not interact with aiortc directly — it sends and receives raw bytes through callbacks registered by
WebRTCConnection. This keeps the stream logic testable without an aiortc dependency.- async close() None
Gracefully close the stream (both read and write sides).
Sends FIN, waits for FIN_ACK (with timeout), then closes.
- get_remote_address() tuple[str, int] | None
Delegate to the connection (data channels share its address).
- on_data(raw: bytes) None
Called by
WebRTCConnectionwhen the data channel receives an SCTP message.Per the libp2p WebRTC spec each SCTP message carries one uvarint length-prefixed protobuf
Message. We decode the length prefix, parse the protobuf, process any flag, and enqueue payload bytes forread().May be invoked from the asyncio bridge thread (not a Trio task). To stay safe we route every Trio primitive call (memory channel,
trio.Event) throughtrio.from_thread.run_sync()with a capturedtrio.lowlevel.TrioToken. When called from within a Trio task (for example in unit tests) we execute the mutations inline.
- async read(n: int | None = None) bytes
Read up to n bytes from the stream.
Blocks until data is available, the remote sends FIN, or the stream is reset.
- Parameters:
n – Maximum bytes to return.
Nonereturns whatever is available in the next message.- Returns:
The bytes read (may be shorter than n).
- Raises:
WebRTCStreamError – If the stream was reset or closed.
- async reset() None
Abruptly terminate the stream.
Sends RESET and immediately tears down without waiting for acknowledgement.
- set_deadline(ttl: int) None
Set a deadline for future read operations.
- Parameters:
ttl – Seconds from now. 0 removes the deadline.
- async write(data: bytes) None
Write data to the stream, length-prefixed-protobuf framed.
Large writes are split into chunks of at most
MAX_PAYLOAD_SIZEbytes so the full framed wire message (uvarint length prefix + protobuf) stays withinMAX_MESSAGE_SIZE.- Raises:
WebRTCStreamError – If the write side is closed or reset.
libp2p.transport.webrtc.transport module
WebRTC Direct transport.
Implements ITransport for the /webrtc-direct multiaddr scheme.
The server publishes its DTLS certificate hash in the multiaddr; the client
constructs an SDP locally — no signaling exchange is needed.
This transport provides native stream multiplexing (data channels), so it
sets provides_native_muxing = True and the swarm skips the
TransportUpgrader.
Spec: https://github.com/libp2p/specs/blob/master/webrtc/webrtc-direct.md
- class libp2p.transport.webrtc.transport.WebRTCDirectTransport(private_key: PrivateKey, config: WebRTCTransportConfig | None = None)
Bases:
ITransportWebRTC Direct transport (
/webrtc-direct).Usage:
transport = WebRTCDirectTransport(private_key=my_key) # Dial a remote peer conn = await transport.dial( Multiaddr("/ip4/1.2.3.4/udp/9090/webrtc-direct/certhash/uEi.../p2p/12D3...") ) # Or create a listener listener = transport.create_listener(handler) await listener.listen(Multiaddr("/ip4/0.0.0.0/udp/9090/webrtc-direct"))
- can_dial(maddr: Multiaddr) bool
Return True if this transport can dial the given multiaddr.
The TransportManager calls this method before attempting a dial to route the connection to the correct transport.
Parameters
- maddrMultiaddr
The multiaddress to check.
Returns
- bool
True if this transport can dial maddr, False otherwise.
Examples
TCP returns True for
/ip4/127.0.0.1/tcp/4001WebSocket returns True for
/ip4/127.0.0.1/tcp/8080/wsQUIC returns True for
/ip4/127.0.0.1/udp/4001/quic-v1
- can_listen(maddr: Multiaddr) bool
Return True if this transport can listen on the given multiaddr.
Often identical to
can_dial()but may differ — e.g. a relay transport can dial outbound but cannot accept inbound connections.Parameters
- maddrMultiaddr
The multiaddress to check.
Returns
- bool
True if this transport can listen on maddr, False otherwise.
- property certificate: WebRTCCertificate
The local DTLS certificate.
- async close() None
Shut down the transport and its asyncio bridge.
Acquires the same lock as
_ensure_bridge()so a concurrent dial cannot resurrect the bridge mid-shutdown.
- create_listener(handler_function: Callable[[ReadWriteCloser], Awaitable[None]]) WebRTCDirectListener
Create a WebRTC Direct listener.
- Parameters:
handler_function – Called with each new inbound connection.
- Returns:
A
WebRTCDirectListener.
- async dial(maddr: Multiaddr) WebRTCConnection
Dial a remote peer over WebRTC Direct.
- Parameters:
maddr – A
/webrtc-directmultiaddr with certhash.- Returns:
A
WebRTCConnection(implements bothIRawConnectionandIMuxedConn).- Raises:
WebRTCConnectionError – If the connection fails.
- protocols() list[str]
Return the list of multiaddr protocol names this transport handles.
Used by
TransportManageras a fast pre-filter: if the multiaddr contains none of the listed protocol names,can_dial/can_listenare not called.Returns
- list[str]
Protocol name strings, e.g.
["tcp"],["ws", "wss"], or["quic", "quic-v1"].
Module contents
WebRTC transport for libp2p.
Provides two transport variants per the libp2p WebRTC specification:
WebRTC Direct (
/webrtc-direct): Server-to-browser or server-to-server connections where the server publishes its certificate hash in the multiaddr. No relay or signaling server is required.WebRTC (
/webrtc): Private-to-private connections where both peers are behind NAT. Uses Circuit Relay v2 for signaling, then upgrades to a direct WebRTC data-channel connection.
Both variants use Noise XX over data-channel 0 for authentication and rely on WebRTC data channels for native stream multiplexing (no Yamux/Mplex needed).
Spec: https://github.com/libp2p/specs/tree/master/webrtc
- class libp2p.transport.webrtc.WebRTCCertificate(certificate: Certificate, private_key: EllipticCurvePrivateKey)
Bases:
objectHolds an ECDSA P-256 certificate and its SHA-256 fingerprint for WebRTC.
Use
generate()to create a fresh self-signed certificate, orfrom_existing()to wrap an already-created certificate/key pair.- fingerprint_to_multibase() str
Encode the fingerprint as a multibase base64url string.
The result can be used directly as the
certhashcomponent in a/webrtc-directmultiaddr.Format:
uprefix + base64url(multihash(sha256(DER cert)))
- fingerprint_to_multihash() bytes
Encode the fingerprint as a multihash (varint code + varint length + digest).
For SHA-256 both code (0x12) and length (32) fit in a single byte, so we avoid a full varint encoder.
- classmethod from_aiortc() WebRTCCertificate
Generate a certificate using aiortc’s
RTCCertificate.Preferred when aiortc is installed because it avoids any cryptography ↔ pyOpenSSL conversion — aiortc’s internal cert is already a
cryptography.x509.Certificate.- Returns:
A new
WebRTCCertificatebacked by an aiortc cert.- Raises:
ImportError – If aiortc is not installed.
WebRTCCertificateError – If certificate generation fails.
- classmethod generate(common_name: str = 'libp2p-webrtc', validity_days: int = 14) WebRTCCertificate
Generate a fresh ECDSA P-256 self-signed certificate.
The spec requires ECDSA with the P-256 curve for browser compatibility.
- Parameters:
common_name – Certificate subject CN.
validity_days – How long the certificate is valid.
- Returns:
A new
WebRTCCertificate.- Raises:
WebRTCCertificateError – If certificate generation fails.
- exception libp2p.transport.webrtc.WebRTCCertificateError
Bases:
WebRTCErrorCertificate generation, parsing, or fingerprint errors.
- exception libp2p.transport.webrtc.WebRTCConnectionError
Bases:
WebRTCError,OpenConnectionErrorICE negotiation, DTLS, or peer connection failure.
- exception libp2p.transport.webrtc.WebRTCError
Bases:
BaseLibp2pErrorBase exception for all WebRTC transport errors.
- exception libp2p.transport.webrtc.WebRTCHandshakeError
Bases:
WebRTCErrorNoise handshake failure over data-channel 0.
- exception libp2p.transport.webrtc.WebRTCMultiaddrError
Bases:
WebRTCErrorInvalid or unparseable WebRTC multiaddr.
- exception libp2p.transport.webrtc.WebRTCSignalingError
Bases:
WebRTCErrorSDP/ICE signaling exchange failure (private-to-private mode).
- exception libp2p.transport.webrtc.WebRTCStreamError
Bases:
WebRTCErrorData-channel stream read/write or lifecycle error.