webrtc

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 5, 2026 License: BSD-3-Clause Imports: 11 Imported by: 0

README

grpc-transports/webrtc

webrtc

Go Reference CI

WebRTC transport layer for gRPC — the carrier for two processes that cannot reach each other. The server exposes a net.Listener over an RTCPeerConnection; the client provides a grpc.DialOption over a data channel. Everything above it is ordinary gRPC — unary, streaming, interceptors, deadlines — because nothing above it knows what it is running on.

Why

gRPC assumes one side can listen and the other can dial. Two peers behind household routers can do neither: neither has an address the other can connect to, and there is nothing in between that either controls. WebRTC is how the web solved that — each side describes itself, the two swap those descriptions by any means at all, and what results is a direct connection.

Encryption DTLS, end to end, not optional — WebRTC has no unencrypted mode
Relay none; the connection is peer to peer
Sidecar none
Dependencies pion/webrtc and gRPC

What it does not do

Signalling. Two peers have to swap a session description before there is anything to carry gRPC over, and how they do that is not a transport's business: a mail, a chat window, a QR code, a rendezvous service somebody already runs. A library that chose one would be choosing for every caller — and the choice is usually already made by whatever the two peers are doing together.

So this takes a peer connection that is already established. What that costs a caller is twenty lines of pion; what it buys is that this package has no opinion about how two people find each other.

Use

Both sides need data channels detached — a channel that delivers to a callback cannot be read from, and a net.Conn is read from:

var engine webrtc.SettingEngine
engine.DetachDataChannels()
api := webrtc.NewAPI(webrtc.WithSettingEngine(engine))

The side that serves:

lis := grpcwebrtc.Listen(peerConnection)
gs := grpc.NewServer()
pb.RegisterYourServiceServer(gs, impl)
go gs.Serve(lis)

The side that calls:

opt, err := grpcwebrtc.DialOption(dataChannel)
cc, err := grpc.NewClient("passthrough:///webrtc",
    opt, grpc.WithTransportCredentials(insecure.NewCredentials()))

Insecure credentials are not a weakening here: WebRTC is encrypted end to end by DTLS and has no unencrypted mode, so a second layer of TLS inside it would be encrypting what is already encrypted, against an attacker who is not there. It is the same reasoning as wss:// in the WebSocket transport beside this one.

The address passed to grpc.NewClient is ignored, because there is no address: the connection already exists and there is nothing to resolve.

Two things a caller should know

A message that does not fit its buffer is an error, not a short read. A data channel carries messages and a net.Conn is a stream, so SCTP hands over one message at a time and what does not fit is gone. This reports the mismatch rather than handing back half a frame that gRPC would fail to parse somewhere far from the cause.

A refused channel does not tell its peer. When a listener has closed and a channel arrives anyway, it is let go of here — but closing a detached channel does not reach the other side. That was measured rather than assumed, and it means a peer whose channel is refused learns it from its own call failing rather than from the channel.

Sibling

grpc-transports/websocket — the carrier that works inside the browser, including under GOOS=js.

License

BSD-3-Clause.

Documentation

Overview

Package webrtc carries gRPC between two processes that cannot reach each other.

What it is for

gRPC assumes one side can listen and the other can dial. Two peers behind household routers can do neither: neither has an address the other can connect to, and there is nothing in between that either controls. WebRTC is how the web solved that — each side describes itself, the two swap those descriptions by any means at all, and what results is a direct connection.

This presents that connection to gRPC as what gRPC expects: a net.Conn on one side and a net.Listener on the other. Everything above it is ordinary gRPC — unary calls, streaming, interceptors, deadlines — because nothing above it knows what it is running on.

What it does not do

It does not do the signalling. Two peers have to swap a session description before there is anything to carry gRPC over, and how they do that is not a transport's business: a mail, a chat window, a QR code, a rendezvous service somebody already runs. A library that chose one would be choosing for every caller, and the choice is usually already made by whatever the two peers are doing together.

So this takes a peer connection that is already established. What that costs a caller is twenty lines of pion; what it buys is that this package has no opinion about how two people find each other.

Index

Constants

This section is empty.

Variables

View Source
var ErrClosed = errors.New("webrtc: listener closed")

ErrClosed is returned by a listener that has been closed.

View Source
var ErrTransport = errors.New("webrtc: transport")

ErrTransport reports a data channel that could not be turned into a connection.

Functions

func Conn

func Conn(dc *pion.DataChannel) (net.Conn, error)

Conn presents an established data channel as a net.Conn, which is what gRPC wants of a transport and all it wants.

The channel is detached from pion's callback delivery first: a gRPC transport reads, and a channel that hands its data to a callback cannot be read from. It must therefore have been created on a peer connection configured with SettingEngine.DetachDataChannels, which is what pion requires and what the examples in this package do.

func DialOption

func DialOption(dc *pion.DataChannel) (grpc.DialOption, error)

DialOption returns a grpc.DialOption that carries every gRPC channel over an established data channel.

Combine it with insecure transport credentials. That is not a weakening: WebRTC is encrypted end to end by DTLS and cannot be otherwise — there is no unencrypted mode to fall back to — so a second layer of TLS inside it would be encrypting what is already encrypted, against an attacker who is not there. It is the same reasoning as wss:// in the WebSocket transport beside this one.

The address a caller passes to grpc.NewClient is ignored, because there is no address: the connection already exists and there is nothing to resolve. Pass "passthrough:///webrtc" so that gRPC does not try.

func Listen

func Listen(pc *pion.PeerConnection) net.Listener

Listen presents a peer connection as a net.Listener, so that a standard grpc.Server can Serve it.

Every data channel the peer opens becomes one connection. That is more than gRPC needs — it multiplexes its own streams over one — but it costs nothing to allow and it is what makes a second gRPC server, or a second client, possible over the same peer connection without a second negotiation.

The peer connection must have been created with a setting engine that detaches data channels; a channel delivering to a callback cannot be read from, and pion says so at detach time rather than here.

Closing the listener stops accepting. It does not close the peer connection, which the caller made and may still be using — for a video call, for instance, which is often exactly what two peers doing this are already on.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL