[tor-commits] [snowflake/master] copy-paste rendezvous works again, but with new interface allowing seamless recovery for the first time
serene at torproject.org
serene at torproject.org
Sun Jun 12 19:44:05 UTC 2016
commit 02562ba7504811659d801d06d9fdb1c3ecfa5d9b
Author: Serene Han <keroserene+git at gmail.com>
Date: Sun Jun 12 12:43:24 2016 -0700
copy-paste rendezvous works again, but with new interface allowing seamless recovery for the first time
---
client/rendezvous.go | 112 +++++++++++++++++++++++++++++++++++++++++++++++++--
client/snowflake.go | 65 +++++-------------------------
client/webrtc.go | 32 +--------------
3 files changed, 122 insertions(+), 87 deletions(-)
diff --git a/client/rendezvous.go b/client/rendezvous.go
index 3b25c89..0acee80 100644
--- a/client/rendezvous.go
+++ b/client/rendezvous.go
@@ -1,15 +1,26 @@
-// WebRTC Rendezvous requires the exchange of SessionDescriptions between
-// peers. This file contains the domain-fronted HTTP signaling mechanism
-// between the client and a desired Broker.
+// WebRTC rendezvous requires the exchange of SessionDescriptions between
+// peers in order to establish a PeerConnection.
+//
+// This file contains the two methods currently available to Snowflake:
+//
+// - Domain-fronted HTTP signaling. The Broker automatically exchange offers
+// and answers between this client and some remote WebRTC proxy.
+// (This is the recommended default, enabled via the flags in "torrc".)
+//
+// - Manual copy-paste signaling. User must create a signaling pipe.
+// (The flags in torrc-manual allow this)
package main
import (
+ "bufio"
"bytes"
"errors"
"io/ioutil"
"log"
"net/http"
"net/url"
+ "os"
+ "syscall"
"github.com/keroserene/go-webrtc"
)
@@ -100,3 +111,98 @@ func (bc *BrokerChannel) Negotiate(offer *webrtc.SessionDescription) (
return nil, errors.New(BrokerErrorUnexpected)
}
}
+
+// Implements the |Tongue| interface to catch snowflakes, using BrokerChannel.
+type WebRTCDialer struct {
+ *BrokerChannel
+ webrtcConfig *webrtc.Configuration
+}
+
+func NewWebRTCDialer(
+ broker *BrokerChannel, iceServers IceServerList) *WebRTCDialer {
+ config := webrtc.NewConfiguration(iceServers...)
+ return &WebRTCDialer{
+ BrokerChannel: broker,
+ webrtcConfig: config,
+ }
+}
+
+// Initialize a WebRTC Connection by signaling through the broker.
+func (w WebRTCDialer) Catch() (*webRTCConn, error) {
+ if nil == w.BrokerChannel {
+ return nil, errors.New("Cannot Dial WebRTC without a BrokerChannel.")
+ }
+ // TODO: [#3] Fetch ICE server information from Broker.
+ // TODO: [#18] Consider TURN servers here too.
+ connection := NewWebRTCConnection(w.webrtcConfig, w.BrokerChannel)
+ err := connection.Connect()
+ return connection, err
+}
+
+// CopyPasteDialer handles the interaction required to copy-paste the
+// offers and answers.
+// Implements |Tongue| interface to catch snowflakes manually.
+// Supports recovery of connections.
+type CopyPasteDialer struct {
+ webrtcConfig *webrtc.Configuration
+ signal *os.File
+ current *webRTCConn
+}
+
+func NewCopyPasteDialer(iceServers IceServerList) *CopyPasteDialer {
+ log.Println("No HTTP signaling detected. Using manual copy-paste signaling.")
+ log.Println("Waiting for a \"signal\" pipe...")
+ // This FIFO receives signaling messages.
+ err := syscall.Mkfifo("signal", 0600)
+ if err != nil {
+ if syscall.EEXIST != err.(syscall.Errno) {
+ log.Fatal(err)
+ }
+ }
+ signalFile, err := os.OpenFile("signal", os.O_RDONLY, 0600)
+ if nil != err {
+ log.Fatal(err)
+ return nil
+ }
+ config := webrtc.NewConfiguration(iceServers...)
+ dialer := &CopyPasteDialer{
+ webrtcConfig: config,
+ signal: signalFile,
+ }
+ go dialer.readSignals()
+ return dialer
+}
+
+// Initialize a WebRTC connection via manual copy-paste.
+func (d *CopyPasteDialer) Catch() (*webRTCConn, error) {
+ if nil == d.signal {
+ return nil, errors.New("Cannot copy-paste dial without signal pipe.")
+ }
+ connection := NewWebRTCConnection(d.webrtcConfig, nil)
+ // Must keep track of pending new connection until copy-paste completes.
+ d.current = connection
+ // Outputs SDP offer to log, expecting user to copy-paste to the remote Peer.
+ // Blocks until user pastes back the answer.
+ err := connection.Connect()
+ d.current = nil
+ return connection, err
+}
+
+// Manual copy-paste signalling.
+func (d *CopyPasteDialer) readSignals() {
+ defer d.signal.Close()
+ log.Printf("CopyPasteDialer: reading messages from signal pipe.")
+ s := bufio.NewScanner(d.signal)
+ for s.Scan() {
+ msg := s.Text()
+ sdp := webrtc.DeserializeSessionDescription(msg)
+ if sdp == nil {
+ log.Printf("CopyPasteDialer: ignoring invalid signal message %+q", msg)
+ continue
+ }
+ d.current.answerChannel <- sdp
+ }
+ if err := s.Err(); err != nil {
+ log.Printf("signal FIFO: %s", err)
+ }
+}
diff --git a/client/snowflake.go b/client/snowflake.go
index 948b862..7c06b17 100644
--- a/client/snowflake.go
+++ b/client/snowflake.go
@@ -2,7 +2,6 @@
package main
import (
- "bufio"
"errors"
"flag"
"io"
@@ -110,45 +109,6 @@ func handler(socks SocksConnector, snowflakes SnowflakeCollector) error {
return nil
}
-func setupCopyPaste() {
- log.Println("No HTTP signaling detected. Waiting for a \"signal\" pipe...")
- // This FIFO receives signaling messages.
- err := syscall.Mkfifo("signal", 0600)
- if err != nil {
- if syscall.EEXIST != err.(syscall.Errno) {
- log.Fatal(err)
- }
- }
- signalFile, err := os.OpenFile("signal", os.O_RDONLY, 0600)
- if nil != err {
- log.Fatal(err)
- }
- defer signalFile.Close()
- go readSignalingMessages(signalFile)
-}
-
-// Manual copy-paste signalling.
-// TODO: Needs fix since multiplexing changes access to the remotes.
-func readSignalingMessages(f *os.File) {
- log.Printf("readSignalingMessages")
- s := bufio.NewScanner(f)
- for s.Scan() {
- msg := s.Text()
- log.Printf("readSignalingMessages loop %+q", msg)
- sdp := webrtc.DeserializeSessionDescription(msg)
- if sdp == nil {
- log.Printf("ignoring invalid signal message %+q", msg)
- continue
- }
- // webrtcRemotes[0].answerChannel <- sdp
- }
- log.Printf("close answerChannel")
- // close(webrtcRemotes[0].answerChannel)
- if err := s.Err(); err != nil {
- log.Printf("signal FIFO: %s", err)
- }
-}
-
func main() {
webrtc.SetLoggingVerbosity(1)
logFile, err := os.OpenFile("snowflake.log",
@@ -169,24 +129,24 @@ func main() {
"capacity for number of multiplexed WebRTC peers")
flag.Parse()
- // TODO: Maybe just get rid of copy-paste option entirely.
- if "" == *brokerURL {
- setupCopyPaste()
- }
-
- // Prepare WebRTC SnowflakeCollector, Broker, then accumulate connections.
+ // Prepare to collect remote WebRTC peers.
snowflakes := NewPeers(*max)
- broker := NewBrokerChannel(*brokerURL, *frontDomain, CreateBrokerTransport())
- snowflakes.Tongue = NewWebRTCDialer(broker, iceServers)
-
- // Use a real logger for traffic.
+ if "" != *brokerURL {
+ // Use potentially domain-fronting broker to rendezvous.
+ broker := NewBrokerChannel(*brokerURL, *frontDomain, CreateBrokerTransport())
+ snowflakes.Tongue = NewWebRTCDialer(broker, iceServers)
+ } else {
+ // Otherwise, use manual copy and pasting of SDP messages.
+ snowflakes.Tongue = NewCopyPasteDialer(iceServers)
+ }
+ // Use a real logger to periodically output how much traffic is happening.
snowflakes.BytesLogger = &BytesSyncLogger{
inboundChan: make(chan int, 5), outboundChan: make(chan int, 5),
inbound: 0, outbound: 0, inEvents: 0, outEvents: 0,
}
+ go snowflakes.BytesLogger.Log()
go ConnectLoop(snowflakes)
- go snowflakes.BytesLogger.Log()
// Begin goptlib client process.
ptInfo, err := pt.ClientSetup(nil)
@@ -197,7 +157,6 @@ func main() {
pt.ProxyError("proxy is not supported")
os.Exit(1)
}
-
listeners := make([]net.Listener, 0)
for _, methodName := range ptInfo.MethodNames {
switch methodName {
@@ -234,9 +193,7 @@ func main() {
for _, ln := range listeners {
ln.Close()
}
-
snowflakes.End()
-
// wait for second signal or no more handlers
sig = nil
for sig == nil && numHandlers != 0 {
diff --git a/client/webrtc.go b/client/webrtc.go
index 7647cf6..2d26b7a 100644
--- a/client/webrtc.go
+++ b/client/webrtc.go
@@ -11,34 +11,6 @@ import (
"time"
)
-// Implements the |Tongue| interface to catch snowflakes, using a BrokerChannel.
-type WebRTCDialer struct {
- *BrokerChannel
- webrtcConfig *webrtc.Configuration
-}
-
-func NewWebRTCDialer(
- broker *BrokerChannel, iceServers IceServerList) *WebRTCDialer {
-
- config := webrtc.NewConfiguration(iceServers...)
- return &WebRTCDialer{
- BrokerChannel: broker,
- webrtcConfig: config,
- }
-}
-
-// Initialize a WebRTC Connection by signaling through the broker.
-func (w WebRTCDialer) Catch() (*webRTCConn, error) {
- if nil == w.BrokerChannel {
- return nil, errors.New("Cannot Dial WebRTC without a BrokerChannel.")
- }
- // TODO: [#3] Fetch ICE server information from Broker.
- // TODO: [#18] Consider TURN servers here too.
- connection := NewWebRTCConnection(w.webrtcConfig, w.BrokerChannel)
- err := connection.Connect()
- return connection, err
-}
-
// Remote WebRTC peer. Implements the |net.Conn| interface.
type webRTCConn struct {
config *webrtc.Configuration
@@ -282,11 +254,11 @@ func (c *webRTCConn) sendOfferToBroker() {
func (c *webRTCConn) exchangeSDP() error {
select {
case offer := <-c.offerChannel:
- // Display for copy-paste, when no broker available.
+ // Display for copy-paste when no broker available.
if nil == c.broker {
log.Printf("Please Copy & Paste the following to the peer:")
log.Printf("----------------")
- log.Printf("\n" + offer.Serialize() + "\n")
+ log.Printf("\n\n" + offer.Serialize() + "\n\n")
log.Printf("----------------")
}
case err := <-c.errorChannel:
More information about the tor-commits
mailing list