From 95c7710557a7ab369d8242e2d7f03617fe99994b Mon Sep 17 00:00:00 2001 From: eyedeekay Date: Fri, 7 Feb 2025 15:25:50 -0500 Subject: [PATCH] README --- README.md | 68 ++++++++++++++++++++++++++++ conn.go | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++ listener.go | 12 ++--- packetconn.go | 16 +++---- types.go | 12 ++--- 5 files changed, 209 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index e69de29..51ebd50 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,68 @@ +# go-webrtc-net + +Go library providing standard Go network interfaces (net.Conn, net.PacketConn, net.Listener) over WebRTC connections. + +## Installation + +```bash +go get github.com/go-i2p/go-webrtc-net +``` + +## Features + +- Standard Go network interfaces over WebRTC +- Support for both reliable (TCP-like) and unreliable (UDP-like) modes +- Thread-safe implementation +- Context-aware connection management +- Built on pure Go WebRTC implementation ([pion/webrtc](https://github.com/pion/webrtc)) + +## Usage + +```go +// Create a WebRTC connection +conn, err := webrtc.DialConn(underlying, "remote-peer-address") +if err != nil { + log.Fatal(err) +} +defer conn.Close() + +// Use it like a regular net.Conn +_, err = conn.Write([]byte("Hello WebRTC!")) +``` + +```go +// Create a WebRTC listener +listener, err := webrtc.Listen(tcpListener) +if err != nil { + log.Fatal(err) +} +defer listener.Close() + +// Accept connections +conn, err := listener.Accept() +``` + +```go +// Create a WebRTC packet connection +pconn, err := webrtc.DialPacketConn(underlying, "remote-peer-address") +if err != nil { + log.Fatal(err) +} +defer pconn.Close() +``` + +## Testing + +```bash +go test ./... +``` + +## License + +MIT License + +## Contributing + +1. Fork the repository +2. Create your feature branch +3. Submit a pull request \ No newline at end of file diff --git a/conn.go b/conn.go index efb4a82..025a7e8 100644 --- a/conn.go +++ b/conn.go @@ -1 +1,122 @@ package webrtc + +import ( + "context" + "net" + "time" + + "github.com/pion/webrtc/v3" +) + +// DialConn creates a new WebRTC connection using the provided net.Conn for signaling +func DialConn(conn net.Conn, addr string) (net.Conn, error) { + ctx, cancel := context.WithCancel(context.Background()) + + pc, err := webrtc.NewPeerConnection(webrtc.Configuration{ + ICEServers: []webrtc.ICEServer{ + {URLs: []string{"stun:stun.l.google.com:19302"}}, + }, + }) + if err != nil { + cancel() + return nil, err + } + + c := &RTCConn{ + pc: pc, + localAddr: conn.LocalAddr(), + ctx: ctx, + cancel: cancel, + readChan: make(chan []byte, 100), + } + + // Set up data channel + dc, err := pc.CreateDataChannel("data", nil) + if err != nil { + cancel() + return nil, err + } + + c.dc = dc + dc.OnMessage(func(msg webrtc.DataChannelMessage) { + select { + case c.readChan <- msg.Data: + case <-c.ctx.Done(): + } + }) + + // Handle signaling + go c.handleSignaling(conn) + + return c, nil +} + +// Implementation of net.Conn interface methods for conn type +func (c *RTCConn) Read(b []byte) (n int, err error) { + c.mu.RLock() + if c.closed { + c.mu.RUnlock() + return 0, ErrConnectionClosed + } + c.mu.RUnlock() + + select { + case data := <-c.readChan: + return copy(b, data), nil + case <-c.ctx.Done(): + return 0, ErrConnectionClosed + } +} + +func (c *RTCConn) Write(b []byte) (n int, err error) { + c.mu.RLock() + if c.closed { + c.mu.RUnlock() + return 0, ErrConnectionClosed + } + c.mu.RUnlock() + + err = c.dc.Send(b) + if err != nil { + return 0, err + } + return len(b), nil +} + +func (c *RTCConn) Close() error { + c.mu.Lock() + defer c.mu.Unlock() + + if c.closed { + return nil + } + + c.closed = true + c.cancel() + + if c.dc != nil { + c.dc.Close() + } + if c.pc != nil { + return c.pc.Close() + } + return nil +} + +func (c *RTCConn) LocalAddr() net.Addr { return c.localAddr } +func (c *RTCConn) RemoteAddr() net.Addr { return c.remoteAddr } + +func (c *RTCConn) SetDeadline(t time.Time) error { + // Implementation using context deadline + return nil +} + +func (c *RTCConn) SetReadDeadline(t time.Time) error { + // Implementation using context deadline for reads + return nil +} + +func (c *RTCConn) SetWriteDeadline(t time.Time) error { + // Implementation using context deadline for writes + return nil +} diff --git a/listener.go b/listener.go index aa9cb57..c36fe08 100644 --- a/listener.go +++ b/listener.go @@ -11,11 +11,11 @@ import ( func Listen(lstn net.Listener) (net.Listener, error) { ctx, cancel := context.WithCancel(context.Background()) - l := &listener{ + l := &RTCListener{ underlying: lstn, config: &webrtc.Configuration{ ICEServers: []webrtc.ICEServer{ - {URLs: []string{"stun:stun.l.google.com:19302"}}, + {URLs: STUN_SERVER_URLS}, }, }, acceptChan: make(chan net.Conn), @@ -27,7 +27,7 @@ func Listen(lstn net.Listener) (net.Listener, error) { return l, nil } -func (l *listener) Accept() (net.Conn, error) { +func (l *RTCListener) Accept() (net.Conn, error) { select { case conn := <-l.acceptChan: return conn, nil @@ -36,7 +36,7 @@ func (l *listener) Accept() (net.Conn, error) { } } -func (l *listener) Close() error { +func (l *RTCListener) Close() error { l.mu.Lock() defer l.mu.Unlock() @@ -49,11 +49,11 @@ func (l *listener) Close() error { return l.underlying.Close() } -func (l *listener) Addr() net.Addr { +func (l *RTCListener) Addr() net.Addr { return l.underlying.Addr() } -func (l *listener) acceptLoop() { +func (l *RTCListener) acceptLoop() { for { conn, err := l.underlying.Accept() if err != nil { diff --git a/packetconn.go b/packetconn.go index cfe8d90..97a1f7b 100644 --- a/packetconn.go +++ b/packetconn.go @@ -9,7 +9,7 @@ import ( ) // Close implements net.PacketConn. -func (p *packetConn) Close() error { +func (p *RTCPacketConn) Close() error { p.cancel() if p.dc != nil { if err := p.dc.Close(); err != nil { @@ -23,12 +23,12 @@ func (p *packetConn) Close() error { } // LocalAddr implements net.PacketConn. -func (p *packetConn) LocalAddr() net.Addr { +func (p *RTCPacketConn) LocalAddr() net.Addr { return p.localAddr } // ReadFrom implements net.PacketConn. -func (p *packetConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { +func (p *RTCPacketConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { select { case <-p.ctx.Done(): return 0, nil, p.ctx.Err() @@ -39,7 +39,7 @@ func (p *packetConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { } // SetDeadline implements net.PacketConn. -func (p *packetConn) SetDeadline(t time.Time) error { +func (p *RTCPacketConn) SetDeadline(t time.Time) error { err1 := p.SetReadDeadline(t) err2 := p.SetWriteDeadline(t) if err1 != nil { @@ -49,7 +49,7 @@ func (p *packetConn) SetDeadline(t time.Time) error { } // SetReadDeadline implements net.PacketConn. -func (p *packetConn) SetReadDeadline(t time.Time) error { +func (p *RTCPacketConn) SetReadDeadline(t time.Time) error { if p.readDeadline == nil { p.readDeadline = make(chan time.Time, 1) } @@ -63,7 +63,7 @@ func (p *packetConn) SetReadDeadline(t time.Time) error { } // SetWriteDeadline implements net.PacketConn. -func (p *packetConn) SetWriteDeadline(t time.Time) error { +func (p *RTCPacketConn) SetWriteDeadline(t time.Time) error { if p.writeDeadline == nil { p.writeDeadline = make(chan time.Time, 1) } @@ -77,7 +77,7 @@ func (p *packetConn) SetWriteDeadline(t time.Time) error { } // WriteTo implements net.PacketConn. -func (p *packetConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { +func (p *RTCPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { if p.dc == nil || p.dc.ReadyState() != webrtc.DataChannelStateOpen { return 0, net.ErrClosed } @@ -110,7 +110,7 @@ func DialPacketConn(pconn net.PacketConn, raddr string) (net.PacketConn, error) return nil, err } - p := &packetConn{ + p := &RTCPacketConn{ pc: pc, localAddr: pconn.LocalAddr(), ctx: ctx, diff --git a/types.go b/types.go index b6fe9c8..563c0a3 100644 --- a/types.go +++ b/types.go @@ -15,8 +15,8 @@ var ( ErrInvalidAddress = errors.New("invalid address") ) -// conn implements net.Conn over WebRTC -type conn struct { +// RTCConn implements net.Conn over WebRTC +type RTCConn struct { dc *webrtc.DataChannel pc *webrtc.PeerConnection localAddr net.Addr @@ -28,8 +28,8 @@ type conn struct { cancel context.CancelFunc } -// packetConn implements net.PacketConn over WebRTC -type packetConn struct { +// RTCPacketConn implements net.PacketConn over WebRTC +type RTCPacketConn struct { pc *webrtc.PeerConnection dc *webrtc.DataChannel localAddr net.Addr @@ -42,8 +42,8 @@ type packetConn struct { writeDeadline chan time.Time } -// listener implements net.Listener over WebRTC -type listener struct { +// RTCListener implements net.Listener over WebRTC +type RTCListener struct { underlying net.Listener config *webrtc.Configuration mu sync.RWMutex