diff --git a/addr_util.go b/addr_util.go new file mode 100644 index 0000000..c4e3c01 --- /dev/null +++ b/addr_util.go @@ -0,0 +1,32 @@ +package libp2pwebrtcdirect + +import ( + "fmt" + "net" + + peer "github.com/libp2p/go-libp2p-peer" + ma "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr-net" +) + +func newMultiaddrFromNetAddr(netAddr net.Addr, peerID peer.ID) (ma.Multiaddr, error) { + tcpMa, err := manet.FromNetAddr(netAddr) + if err != nil { + return nil, fmt.Errorf("failed create ma: %v", err) + } + httpMa := tcpMa.Encapsulate(httpma) + webrtcMa, err := ma.NewMultiaddr("/p2p-webrtc/" + peer.IDB58Encode(peerID)) + if err != nil { + return nil, err + } + maAddr := httpMa.Encapsulate(webrtcMa) + return maAddr, nil +} + +func getPeerIDFromMultiAddr(addr ma.Multiaddr) (peer.ID, error) { + idString, err := addr.ValueForProtocol(protoCode) + if err != nil { + return "", err + } + return peer.IDB58Decode(idString) +} diff --git a/conn.go b/conn.go index 41c5437..f785e72 100644 --- a/conn.go +++ b/conn.go @@ -27,21 +27,32 @@ type connConfig struct { addr net.Addr isServer bool remoteID peer.ID + localID peer.ID } -func newConnConfig(transport *Transport, maAddr ma.Multiaddr, isServer bool) (*connConfig, error) { - httpMa := maAddr.Decapsulate(webrtcma) - +func getNetAddr(addr ma.Multiaddr) (net.Addr, error) { + if !Fmt.Matches(addr) { + return nil, fmt.Errorf("misformatted multiaddress: %q (expected %q)", addr.String(), Fmt.String()) + } + httpMa, _ := ma.SplitLast(addr) tcpMa := httpMa.Decapsulate(httpma) - addr, err := manet.ToNetAddr(tcpMa) + netAddr, err := manet.ToNetAddr(tcpMa) if err != nil { return nil, fmt.Errorf("failed to get net addr: %v", err) } + return netAddr, nil +} + +func newConnConfig(transport *Transport, maAddr ma.Multiaddr, isServer bool) (*connConfig, error) { + netAddr, err := getNetAddr(maAddr) + if err != nil { + return nil, err + } return &connConfig{ transport: transport, maAddr: maAddr, - addr: addr, + addr: netAddr, isServer: isServer, }, nil } diff --git a/go.mod b/go.mod index 83b7737..fa6b1a3 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/libp2p/go-libp2p-peerstore v0.0.1 github.com/libp2p/go-libp2p-transport v0.0.4 github.com/libp2p/go-stream-muxer v0.0.1 + github.com/libp2p/go-ws-transport v0.0.1 github.com/multiformats/go-multiaddr v0.0.2 github.com/multiformats/go-multiaddr-fmt v0.0.1 github.com/multiformats/go-multiaddr-net v0.0.1 @@ -23,6 +24,7 @@ require ( github.com/pions/datachannel v1.2.2-0.20190402055840-9276b506f1f3 github.com/pions/quic-go v0.10.2 // indirect github.com/pions/webrtc v1.2.1-0.20190402062217-69e5725007d2 + github.com/stretchr/testify v1.3.0 github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc github.com/whyrusleeping/go-smux-multiplex v3.0.16+incompatible golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c // indirect diff --git a/go.sum b/go.sum index 02ea5f5..7e9a8ba 100644 --- a/go.sum +++ b/go.sum @@ -55,7 +55,7 @@ github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324 h1:PV190X5/DzQ/tbFFG5Y github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= github.com/ipfs/go-cid v0.0.1 h1:GBjWPktLnNyX0JiQCNFpUuUSoMw5KMyqrsejHYlILBE= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.0.1/go.mod h1:bYmHO9fuKO1Ca7dpdDBWQl0mndy5b0HFqSJjGlNYtzs= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= diff --git a/listener.go b/listener.go index 2cddfff..239b866 100644 --- a/listener.go +++ b/listener.go @@ -9,7 +9,6 @@ import ( tpt "github.com/libp2p/go-libp2p-transport" ma "github.com/multiformats/go-multiaddr" - manet "github.com/multiformats/go-multiaddr-net" ) // Listener is an interface closely resembling the net.Listener interface. @@ -28,14 +27,10 @@ func newListener(config *connConfig) (*Listener, error) { } // Update the addr after listening - tcpMa, err := manet.FromNetAddr(ln.Addr()) + maAddr, err := newMultiaddrFromNetAddr(ln.Addr(), config.localID) if err != nil { - return nil, fmt.Errorf("failed create ma: %v", err) + return nil, err } - - httpMa := tcpMa.Encapsulate(httpma) - maAddr := httpMa.Encapsulate(webrtcma) - config.addr = ln.Addr() config.maAddr = maAddr diff --git a/protocol.go b/protocol.go new file mode 100644 index 0000000..8510bc5 --- /dev/null +++ b/protocol.go @@ -0,0 +1,54 @@ +package libp2pwebrtcdirect + +import ( + "fmt" + + peer "github.com/libp2p/go-libp2p-peer" + ma "github.com/multiformats/go-multiaddr" +) + +func init() { + if err := ma.AddProtocol(Protocol); err != nil { + panic(fmt.Errorf("error registering p2p-webrtc protocol: %s", err)) + } +} + +const protoCode = 0x1992 + +var Protocol = ma.Protocol{ + Name: "p2p-webrtc", + Code: protoCode, + VCode: ma.CodeToVarint(protoCode), + Size: -1, + Transcoder: Transcoder, +} + +var Transcoder ma.Transcoder = transcoder{} + +// transcoder handles encoding/decoding peer ids as base58. +type transcoder struct { + strtobyte func(string) ([]byte, error) + bytetostr func([]byte) (string, error) + validbyte func([]byte) error +} + +func (t transcoder) StringToBytes(s string) ([]byte, error) { + id, err := peer.IDB58Decode(s) + if err != nil { + return nil, err + } + return []byte(id), nil +} + +func (t transcoder) BytesToString(b []byte) (string, error) { + id, err := peer.IDFromBytes(b) + if err != nil { + return "", err + } + return peer.IDB58Encode(id), nil +} + +func (t transcoder) ValidateBytes(b []byte) error { + _, err := peer.IDFromBytes(b) + return err +} diff --git a/transport.go b/transport.go index b5dcbd5..6655cd8 100644 --- a/transport.go +++ b/transport.go @@ -6,12 +6,19 @@ import ( peer "github.com/libp2p/go-libp2p-peer" tpt "github.com/libp2p/go-libp2p-transport" + transport "github.com/libp2p/go-libp2p-transport" smux "github.com/libp2p/go-stream-muxer" ma "github.com/multiformats/go-multiaddr" mafmt "github.com/multiformats/go-multiaddr-fmt" "github.com/pions/webrtc" ) +// Ensure that our Transport implements the correct interface. +var _ transport.Transport = &Transport{} + +// Fmt is the Multiaddress format for WebRTC +var Fmt = mafmt.And(mafmt.HTTP, mafmt.Base(Protocol.Code)) + // Transport is the WebRTC transport. type Transport struct { webrtcOptions webrtc.Configuration @@ -39,7 +46,7 @@ func NewTransport(webrtcOptions webrtc.Configuration, muxer smux.Transport) *Tra // CanDial returns true if this transport believes it can dial the given // multiaddr. func (t *Transport) CanDial(addr ma.Multiaddr) bool { - return mafmt.WebRTCDirect.Matches(addr) + return Fmt.Matches(addr) } // Dial dials the peer at the remote address. @@ -48,11 +55,12 @@ func (t *Transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tp return nil, fmt.Errorf("can't dial address %s", raddr) } + // TODO: Check that the peer id in raddr is equal to p. + cfg, err := newConnConfig(t, raddr, false) if err != nil { return nil, fmt.Errorf("failed to get dial args: %v", err) } - cfg.remoteID = p conn, err := dial(ctx, cfg) @@ -73,6 +81,11 @@ func (t *Transport) Listen(laddr ma.Multiaddr) (tpt.Listener, error) { if err != nil { return nil, fmt.Errorf("failed to get dial args: %v", err) } + localID, err := getPeerIDFromMultiAddr(laddr) + if err != nil { + return nil, err + } + cfg.localID = localID l, err := newListener(cfg) if err != nil { @@ -84,14 +97,14 @@ func (t *Transport) Listen(laddr ma.Multiaddr) (tpt.Listener, error) { // Protocols returns the list of terminal protocols this transport can dial. func (t *Transport) Protocols() []int { - return []int{ma.P_P2P_WEBRTC_DIRECT} + return []int{protoCode} } -// Proxy always returns false for the TCP transport. +// Proxy always returns false for the WebRTC transport. func (t *Transport) Proxy() bool { return false } func (t *Transport) String() string { - return "p2p-webrtc-direct" + return "p2p-webrtc" } diff --git a/webrtcdirect.go b/webrtcdirect.go index 92bf88f..5329206 100644 --- a/webrtcdirect.go +++ b/webrtcdirect.go @@ -9,7 +9,6 @@ import ( var log = logging.Logger("webrtcdirect-tpt") -var webrtcma, _ = ma.NewMultiaddr("/p2p-webrtc-direct") var httpma, _ = ma.NewMultiaddr("/http") var _ tpt.Transport = &Transport{} diff --git a/webrtcdirect_test.go b/webrtcdirect_test.go index 51c6052..27a7c65 100644 --- a/webrtcdirect_test.go +++ b/webrtcdirect_test.go @@ -1,16 +1,32 @@ package libp2pwebrtcdirect import ( + "math/rand" "testing" logging "github.com/ipfs/go-log" - + crypto "github.com/libp2p/go-libp2p-crypto" + peer "github.com/libp2p/go-libp2p-peer" utils "github.com/libp2p/go-libp2p-transport/test" ma "github.com/multiformats/go-multiaddr" "github.com/pions/webrtc" mplex "github.com/whyrusleeping/go-smux-multiplex" ) +func newTestPeerID(t *testing.T) peer.ID { + t.Helper() + seededReader := rand.New(rand.NewSource(12345678)) + priv, _, err := crypto.GenerateEd25519Key(seededReader) + if err != nil { + t.Fatal(err) + } + id, err := peer.IDFromPrivateKey(priv) + if err != nil { + t.Fatal(err) + } + return id +} + func TestTransport(t *testing.T) { logging.SetLogLevel("*", "warning") @@ -23,8 +39,9 @@ func TestTransport(t *testing.T) { new(mplex.Transport), ) - addr := "/ip4/127.0.0.1/tcp/0/http/p2p-webrtc-direct" - utils.SubtestTransport(t, ta, tb, addr, "peerA") + peerID := newTestPeerID(t) + addr := "/ip4/127.0.0.1/tcp/0/http/p2p-webrtc/" + peer.IDB58Encode(peerID) + utils.SubtestTransport(t, ta, tb, addr, peerID) } func TestTransportCantListenUtp(t *testing.T) {