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),
)
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"
}
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 "<WebRTC>"
+ // 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
}
}
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)
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,
})
})
})
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 {