commit 4ca0a3aa0a964e23549a7088cb14c8e1a0f932a5 Author: Serene Han keroserene+git@gmail.com Date: Mon Jun 13 11:05:26 2016 -0700
improve client interface specificity and composability which eliminates much unnecessary code --- client/client_test.go | 87 ++++++++++++++++++++++----------------------------- client/interfaces.go | 24 ++++++++++++-- client/peers.go | 8 ++--- client/rendezvous.go | 4 +-- client/snowflake.go | 34 ++++++++++---------- client/webrtc.go | 47 +++++++++++----------------- 6 files changed, 100 insertions(+), 104 deletions(-)
diff --git a/client/client_test.go b/client/client_test.go index de83768..87fb2cb 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -47,7 +47,7 @@ func (m *MockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
type FakeDialer struct{}
-func (w FakeDialer) Catch() (*webRTCConn, error) { +func (w FakeDialer) Catch() (Snowflake, error) { fmt.Println("Caught a dummy snowflake.") return &webRTCConn{}, nil } @@ -65,57 +65,10 @@ func (f FakeSocksConn) Grant(addr *net.TCPAddr) error { return nil }
type FakePeers struct{ toRelease *webRTCConn }
-func (f FakePeers) Collect() error { return nil } -func (f FakePeers) Pop() *webRTCConn { return nil } +func (f FakePeers) Collect() error { return nil } +func (f FakePeers) Pop() Snowflake { return nil }
func TestSnowflakeClient(t *testing.T) { - SkipConvey("WebRTC ConnectLoop", t, func() { - Convey("WebRTC ConnectLoop continues until capacity of 1.\n", func() { - snowflakes := NewPeers(1) - snowflakes.Tongue = FakeDialer{} - - go ConnectLoop(snowflakes) - // <-snowflakes.maxedChan - - So(snowflakes.Count(), ShouldEqual, 1) - r := <-snowflakes.snowflakeChan - So(r, ShouldNotBeNil) - So(snowflakes.Count(), ShouldEqual, 0) - }) - - Convey("WebRTC ConnectLoop continues until capacity of 3.\n", func() { - snowflakes := NewPeers(3) - snowflakes.Tongue = FakeDialer{} - - go ConnectLoop(snowflakes) - // <-snowflakes.maxedChan - So(snowflakes.Count(), ShouldEqual, 3) - <-snowflakes.snowflakeChan - <-snowflakes.snowflakeChan - <-snowflakes.snowflakeChan - So(snowflakes.Count(), ShouldEqual, 0) - }) - - Convey("WebRTC ConnectLoop continues filling when Snowflakes disconnect.\n", func() { - snowflakes := NewPeers(3) - snowflakes.Tongue = FakeDialer{} - - go ConnectLoop(snowflakes) - // <-snowflakes.maxedChan - So(snowflakes.Count(), ShouldEqual, 3) - - r := <-snowflakes.snowflakeChan - So(snowflakes.Count(), ShouldEqual, 2) - r.Close() - // <-snowflakes.maxedChan - So(snowflakes.Count(), ShouldEqual, 3) - - <-snowflakes.snowflakeChan - <-snowflakes.snowflakeChan - <-snowflakes.snowflakeChan - So(snowflakes.Count(), ShouldEqual, 0) - }) - })
Convey("Peers", t, func() { Convey("Can construct", func() { @@ -183,6 +136,17 @@ func TestSnowflakeClient(t *testing.T) { So(p.Count(), ShouldEqual, 2) })
+ Convey("End Closes all peers.", func() { + cnt := 5 + p := NewPeers(cnt) + for i := 0; i < cnt; i++ { + p.activePeers.PushBack(&webRTCConn{}) + } + So(p.Count(), ShouldEqual, cnt) + p.End() + So(p.Count(), ShouldEqual, 0) + }) + })
Convey("Snowflake", t, func() { @@ -253,6 +217,29 @@ func TestSnowflakeClient(t *testing.T) { }) })
+ Convey("Dialers", t, func() { + Convey("Can construct WebRTCDialer.", func() { + broker := &BrokerChannel{Host: "test"} + d := NewWebRTCDialer(broker, nil) + So(d, ShouldNotBeNil) + So(d.BrokerChannel, ShouldNotBeNil) + So(d.BrokerChannel.Host, ShouldEqual, "test") + }) + Convey("WebRTCDialer cannot Catch a snowflake with nil broker.", func() { + d := NewWebRTCDialer(nil, nil) + conn, err := d.Catch() + So(conn, ShouldBeNil) + So(err, ShouldNotBeNil) + }) + SkipConvey("WebRTCDialer can Catch a snowflake.", func() { + broker := &BrokerChannel{Host: "test"} + d := NewWebRTCDialer(broker, nil) + conn, err := d.Catch() + So(conn, ShouldBeNil) + So(err, ShouldNotBeNil) + }) + }) + Convey("Rendezvous", t, func() { webrtc.SetLoggingVerbosity(0) transport := &MockTransport{http.StatusOK} diff --git a/client/interfaces.go b/client/interfaces.go index ba49a92..4fb0dcf 100644 --- a/client/interfaces.go +++ b/client/interfaces.go @@ -1,13 +1,31 @@ -// In the Client context, "Snowflake" refers to a remote browser proxy. package main
import ( + "io" "net" )
+type Connector interface { + Connect() error +} + +type Resetter interface { + Reset() + WaitForReset() +} + +// Interface for a single remote WebRTC peer. +// In the Client context, "Snowflake" refers to the remote browser proxy. +type Snowflake interface { + io.ReadWriter + Resetter + Connector + Close() error +} + // Interface for catching Snowflakes. (aka the remote dialer) type Tongue interface { - Catch() (*webRTCConn, error) + Catch() (Snowflake, error) }
// Interface for collecting some number of Snowflakes, for passing along @@ -19,7 +37,7 @@ type SnowflakeCollector interface { Collect() error
// Remove and return the most available Snowflake from the collection. - Pop() *webRTCConn + Pop() Snowflake }
// Interface to adapt to goptlib's SocksConn struct. diff --git a/client/peers.go b/client/peers.go index 734fdfe..eb435fd 100644 --- a/client/peers.go +++ b/client/peers.go @@ -22,7 +22,7 @@ type Peers struct { Tongue BytesLogger
- snowflakeChan chan *webRTCConn + snowflakeChan chan Snowflake activePeers *list.List capacity int } @@ -31,7 +31,7 @@ type Peers struct { func NewPeers(max int) *Peers { p := &Peers{capacity: max} // Use buffered go channel to pass snowflakes onwards to the SOCKS handler. - p.snowflakeChan = make(chan *webRTCConn, max) + p.snowflakeChan = make(chan Snowflake, max) p.activePeers = list.New() return p } @@ -59,7 +59,7 @@ func (p *Peers) Collect() error { }
// As part of |SnowflakeCollector| interface. -func (p *Peers) Pop() *webRTCConn { +func (p *Peers) Pop() Snowflake {
// Blocks until an available snowflake appears. snowflake, ok := <-p.snowflakeChan @@ -67,7 +67,7 @@ func (p *Peers) Pop() *webRTCConn { return nil } // Set to use the same rate-limited traffic logger to keep consistency. - snowflake.BytesLogger = p.BytesLogger + snowflake.(*webRTCConn).BytesLogger = p.BytesLogger return snowflake }
diff --git a/client/rendezvous.go b/client/rendezvous.go index 0acee80..6c7aa44 100644 --- a/client/rendezvous.go +++ b/client/rendezvous.go @@ -128,7 +128,7 @@ func NewWebRTCDialer( }
// Initialize a WebRTC Connection by signaling through the broker. -func (w WebRTCDialer) Catch() (*webRTCConn, error) { +func (w WebRTCDialer) Catch() (Snowflake, error) { if nil == w.BrokerChannel { return nil, errors.New("Cannot Dial WebRTC without a BrokerChannel.") } @@ -174,7 +174,7 @@ func NewCopyPasteDialer(iceServers IceServerList) *CopyPasteDialer { }
// Initialize a WebRTC connection via manual copy-paste. -func (d *CopyPasteDialer) Catch() (*webRTCConn, error) { +func (d *CopyPasteDialer) Catch() (Snowflake, error) { if nil == d.signal { return nil, errors.New("Cannot copy-paste dial without signal pipe.") } diff --git a/client/snowflake.go b/client/snowflake.go index 7c06b17..9f5cdc7 100644 --- a/client/snowflake.go +++ b/client/snowflake.go @@ -26,21 +26,6 @@ const ( // ends, -1 is written. var handlerChan = make(chan int)
-func copyLoop(a, b net.Conn) { - var wg sync.WaitGroup - wg.Add(2) - go func() { - io.Copy(b, a) - wg.Done() - }() - go func() { - io.Copy(a, b) - wg.Done() - }() - wg.Wait() - log.Println("copy loop ended") -} - // Maintain |SnowflakeCapacity| number of available WebRTC connections, to // transfer to the Tor SOCKS handler when needed. func ConnectLoop(snowflakes SnowflakeCollector) { @@ -104,11 +89,28 @@ func handler(socks SocksConnector, snowflakes SnowflakeCollector) error {
// When WebRTC resets, close the SOCKS connection, which induces new handler. // TODO: Double check this / fix it. - <-snowflake.reset + snowflake.WaitForReset() log.Println("---- Closed ---") return nil }
+// Exchanges bytes between two ReadWriters. +// (In this case, between a SOCKS and WebRTC connection.) +func copyLoop(a, b io.ReadWriter) { + var wg sync.WaitGroup + wg.Add(2) + go func() { + io.Copy(b, a) + wg.Done() + }() + go func() { + io.Copy(a, b) + wg.Done() + }() + wg.Wait() + log.Println("copy loop ended") +} + func main() { webrtc.SetLoggingVerbosity(1) logFile, err := os.OpenFile("snowflake.log", diff --git a/client/webrtc.go b/client/webrtc.go index 2d26b7a..c7a46ea 100644 --- a/client/webrtc.go +++ b/client/webrtc.go @@ -3,15 +3,15 @@ package main import ( "bytes" "errors" - "fmt" "github.com/keroserene/go-webrtc" "io" "log" - "net" "time" )
-// Remote WebRTC peer. Implements the |net.Conn| interface. +// Remote WebRTC peer. +// Implements the |Snowflake| interface, which includes +// |io.ReadWriter|, |Resetter|, and |Connector|. type webRTCConn struct { config *webrtc.Configuration pc *webrtc.PeerConnection @@ -33,11 +33,14 @@ type webRTCConn struct { BytesLogger }
+// Read bytes from remote WebRTC. +// As part of |io.ReadWriter| func (c *webRTCConn) Read(b []byte) (int, error) { return c.recvPipe.Read(b) }
-// Writes bytes out to the snowflake proxy. +// Writes bytes out to remote WebRTC. +// As part of |io.ReadWriter| func (c *webRTCConn) Write(b []byte) (int, error) { c.BytesLogger.AddOutbound(len(b)) if nil == c.snowflake { @@ -49,6 +52,7 @@ func (c *webRTCConn) Write(b []byte) (int, error) { return len(b), nil }
+// As part of |Snowflake| func (c *webRTCConn) Close() error { var err error = nil log.Printf("WebRTC: Closing") @@ -67,25 +71,17 @@ func (c *webRTCConn) Close() error { return err }
-func (c *webRTCConn) LocalAddr() net.Addr { - return nil -} - -func (c *webRTCConn) RemoteAddr() net.Addr { - return nil -} - -func (c *webRTCConn) SetDeadline(t time.Time) error { - return fmt.Errorf("SetDeadline not implemented") -} - -func (c *webRTCConn) SetReadDeadline(t time.Time) error { - return fmt.Errorf("SetReadDeadline not implemented") +// As part of |Resetter| +func (c *webRTCConn) Reset() { + go func() { + c.reset <- struct{}{} + log.Println("WebRTC resetting...") + }() + c.Close() }
-func (c *webRTCConn) SetWriteDeadline(t time.Time) error { - return fmt.Errorf("SetWriteDeadline not implemented") -} +// As part of |Resetter| +func (c *webRTCConn) WaitForReset() { <-c.reset }
// Construct a WebRTC PeerConnection. func NewWebRTCConnection(config *webrtc.Configuration, @@ -108,6 +104,7 @@ func NewWebRTCConnection(config *webrtc.Configuration, return connection }
+// As part of |Connector| interface. func (c *webRTCConn) Connect() error { log.Printf("Establishing WebRTC connection #%d...", c.index) // TODO: When go-webrtc is more stable, it's possible that a new @@ -287,14 +284,6 @@ func (c *webRTCConn) exchangeSDP() error { return nil }
-func (c *webRTCConn) Reset() { - go func() { - c.reset <- struct{}{} - log.Println("WebRTC resetting...") - }() - c.Close() -} - func (c *webRTCConn) cleanup() { if nil != c.snowflake { log.Printf("WebRTC: closing DataChannel")
tor-commits@lists.torproject.org