torrent.go | 12 ++++++++++-- webrtc.go | 35 ++++++++++++++++++++++++++--------- webtorrent/tracker-client.go | 29 +++++++++++++++++++---------- diff --git a/torrent.go b/torrent.go index 8e83d3d38a252361eca585629e07218fb87dafbe..3e74df6394d160eec83a4fc31015c03938c20476 100644 --- a/torrent.go +++ b/torrent.go @@ -1532,13 +1532,21 @@ c datachannel.ReadWriteCloser, dcc webtorrent.DataChannelContext, ) { defer c.Close() + netConn := webrtcNetConn{ + ReadWriteCloser: c, + DataChannelContext: dcc, + } + peerRemoteAddr := netConn.RemoteAddr() + if t.cl.badPeerAddr(peerRemoteAddr) { + return + } pc, err := t.cl.initiateProtocolHandshakes( context.Background(), - webrtcNetConn{c, dcc}, + netConn, t, dcc.LocalOffered, false, - webrtcNetAddr{dcc.Remote}, + netConn.RemoteAddr(), webrtcNetwork, fmt.Sprintf("webrtc offer_id %x", dcc.OfferId), ) diff --git a/webrtc.go b/webrtc.go index e8b0213cd7aa89d72a9ee216ab977d1e91a434f1..44ef6ca24099a1a88a7c966806350d99a370840b 100644 --- a/webrtc.go +++ b/webrtc.go @@ -1,13 +1,13 @@ package torrent import ( + "fmt" "net" "time" + "github.com/anacrolix/torrent/webtorrent" "github.com/pion/datachannel" "github.com/pion/webrtc/v3" - - "github.com/anacrolix/torrent/webtorrent" ) const webrtcNetwork = "webrtc" @@ -18,34 +18,51 @@ webtorrent.DataChannelContext } type webrtcNetAddr struct { - webrtc.SessionDescription + *webrtc.ICECandidate } +var _ net.Addr = webrtcNetAddr{} + func (webrtcNetAddr) Network() string { + // Now that we have the ICE candidate, we can tell if it's over udp or tcp. But should we use + // that for the network? return webrtcNetwork } func (me webrtcNetAddr) String() string { - // TODO: What can I show here that's more like other protocols? - return "" + // Probably makes sense to return the IP:port expected of most net.Addrs. I'm not sure if + // Address would be quoted for IPv6 already. If not, net.JoinHostPort might be appropriate. + return fmt.Sprintf("%s:%d", me.Address, me.Port) } func (me webrtcNetConn) LocalAddr() net.Addr { - return webrtcNetAddr{me.Local} + // I'm not sure if this evolves over time. It might also be unavailable if the PeerConnection is + // closed or closes itself. The same concern applies to RemoteAddr. + pair, err := me.DataChannelContext.GetSelectedIceCandidatePair() + if err != nil { + panic(err) + } + return webrtcNetAddr{pair.Local} } func (me webrtcNetConn) RemoteAddr() net.Addr { - return webrtcNetAddr{me.Remote} + // See comments on LocalAddr. + pair, err := me.DataChannelContext.GetSelectedIceCandidatePair() + if err != nil { + panic(err) + } + return webrtcNetAddr{pair.Remote} } +// Do we need these for WebRTC connections exposed as net.Conns? Can we set them somewhere inside +// PeerConnection or on the channel or some transport? + func (w webrtcNetConn) SetDeadline(t time.Time) error { return nil } - func (w webrtcNetConn) SetReadDeadline(t time.Time) error { return nil } - func (w webrtcNetConn) SetWriteDeadline(t time.Time) error { return nil } diff --git a/webtorrent/tracker-client.go b/webtorrent/tracker-client.go index 9f02c7e785f38e7767e86e73f3304eb61a322ef8..1ec4b9d9c6f917200c2795665283a2ad8e286df9 100644 --- a/webtorrent/tracker-client.go +++ b/webtorrent/tracker-client.go @@ -58,10 +58,17 @@ infoHash [20]byte } type DataChannelContext struct { + // Can these be obtained by just calling the relevant methods on peerConnection? Local, Remote webrtc.SessionDescription OfferId string LocalOffered bool InfoHash [20]byte + // This is private as some methods might not be appropriate with data channel context. + peerConnection *wrappedPeerConnection +} + +func (me *DataChannelContext) GetSelectedIceCandidatePair() (*webrtc.ICECandidatePair, error) { + return me.peerConnection.SCTP().Transport().ICETransport().GetSelectedCandidatePair() } type onDataChannelOpen func(_ datachannel.ReadWriteCloser, dcc DataChannelContext) @@ -318,11 +325,12 @@ tc.mu.Lock() tc.stats.ConvertedInboundConns++ tc.mu.Unlock() tc.OnConn(dc, DataChannelContext{ - Local: answer, - Remote: offer, - OfferId: offerId, - LocalOffered: false, - InfoHash: infoHash, + Local: answer, + Remote: offer, + OfferId: offerId, + LocalOffered: false, + InfoHash: infoHash, + peerConnection: peerConnection, }) }) }) @@ -345,11 +353,12 @@ tc.mu.Lock() tc.stats.ConvertedOutboundConns++ tc.mu.Unlock() tc.OnConn(dc, DataChannelContext{ - Local: offer.originalOffer, - Remote: answer, - OfferId: offerId, - LocalOffered: true, - InfoHash: offer.infoHash, + Local: offer.originalOffer, + Remote: answer, + OfferId: offerId, + LocalOffered: true, + InfoHash: offer.infoHash, + peerConnection: offer.peerConnection, }) }) if err != nil {