Commit 5eb77569 authored by Arlo Breault's avatar Arlo Breault
Browse files

Try to use named pipe on the server to start as well

parent 0d2261e7
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -5,5 +5,5 @@
.DS_Store
datadir/
client/snowflake
server/snowflake
server/server
snowflake.log
+87 −140
Original line number Diff line number Diff line
@@ -12,25 +12,22 @@ import (
	"syscall"
	"time"

	"git.torproject.org/pluggable-transports/goptlib.git"
	"github.com/keroserene/go-webrtc"
	"github.com/keroserene/go-webrtc/data"

	"git.torproject.org/pluggable-transports/goptlib.git"
)

var ptMethodName = "snowflake"
var ptInfo pt.ServerInfo
var logFile *os.File

// When a connection handler starts, +1 is written to this channel; when it
// ends, -1 is written.
// When a datachannel handler starts, +1 is written to this channel;
// when it ends, -1 is written.
var handlerChan = make(chan int)

var signalChan = make(chan *webrtc.SessionDescription)

func copyLoop(a, b net.Conn) {
	var wg sync.WaitGroup
	wg.Add(2)

	go func() {
		io.Copy(b, a)
		wg.Done()
@@ -39,28 +36,25 @@ func copyLoop(a, b net.Conn) {
		io.Copy(a, b)
		wg.Done()
	}()

	wg.Wait()
}

type webRTCConn struct {
	pc       *webrtc.PeerConnection
	dc *data.Channel
	recvPipe *io.PipeReader
	pc *webrtc.PeerConnection
	pr *io.PipeReader
}

func (c *webRTCConn) Read(b []byte) (int, error) {
	return c.recvPipe.Read(b)
	return c.pr.Read(b)
}

func (c *webRTCConn) Write(b []byte) (int, error) {
	log.Printf("webrtc Write %d %q", len(b), string(b))
	dc.Send(b)
	c.dc.Send(b)
	return len(b), nil
}

func (c *webRTCConn) Close() error {
	// Data channel closed implicitly?
	return c.pc.Close()
}

@@ -84,169 +78,125 @@ func (c *webRTCConn) SetWriteDeadline(t time.Time) error {
	return fmt.Errorf("SetWriteDeadline not implemented")
}

type webRTCListener struct {
	peerConnectionChan chan *webrtc.PeerConnection
	stopChan           chan struct{}
}

func (ln *webRTCListener) Accept() (net.Conn, error) {
	offer, ok := <-signalChan
	if !ok {
		return nil, fmt.Errorf("signal channel closed")
	}

	pc, ok := <-ln.peerConnectionChan
	if !ok {
		return nil, fmt.Errorf("PeerConnection channel closed")
	}
func datachannelHandler(conn *webRTCConn) {
	handlerChan <- 1
	defer func() {
		handlerChan <- -1
	}()

	err := pc.SetRemoteDescription(offer)
	or, err := pt.DialOr(&ptInfo, "", ptMethodName) // TODO: Extended OR
	if err != nil {
		return nil, err
		log.Printf("Failed to connect to ORPort: " + err.Error())
		return
	}
	defer or.Close()

	go func() {
		answer, err := pc.CreateAnswer()
		if err != nil {
			// signal error upwards
			fmt.Println(err)
			return
	pr, pw := io.Pipe()
	conn.pr = pr

	dc := conn.dc
	dc.OnClose = func() {
		pw.Close()
	}
		err = pc.SetLocalDescription(answer)
	dc.OnMessage = func(msg []byte) {
		n, err := pw.Write(msg)
		if err != nil {
			// signal error upwards
			fmt.Println(err)
			return
			pw.CloseWithError(err)
		}
	}()

	select {
	case conn := <-ln.connChan:
		return conn, nil
	case err := <-ln.errChan:
		return nil, err
	}

	return &webRTCConn{pc: pc, dc: dc, recvPipe: nil}, nil
		if n != len(msg) {
			panic("short write")
		}

func (ln *webRTCListener) Close() error {
	// Stop the PeerConnection factory goroutine.
	close(ln.stopChan)
	return nil
	}

func (ln *webRTCListener) Addr() net.Addr {
	return &net.TCPAddr{IP: net.IPv4zero, Port: 1}
	copyLoop(conn, or)
}

func makePeerConnection(config *webrtc.Configuration) (*webrtc.PeerConnection, error) {
	pc, err := webrtc.NewPeerConnection(config)

	if err != nil {
		log.Printf("NewPeerConnection: %s", err)
		return nil, err
	}

	pc.OnNegotiationNeeded = func() {
		log.Println("OnNegotiationNeeded")
		panic("OnNegotiationNeeded")
	}
	pc.OnIceCandidate = func(candidate webrtc.IceCandidate) {
		log.Printf("OnIceCandidate %s", candidate.Serialize())
		// Allow candidates to accumulate until OnIceComplete.
	}
	pc.OnIceComplete = func() {
		log.Printf("OnIceComplete")
	}
	pc.OnDataChannel = func(channel *data.Channel) {
	pc.OnDataChannel = func(dc *data.Channel) {
		log.Println("OnDataChannel")
		panic("OnDataChannel")
		datachannelHandler(&webRTCConn{pc: pc, dc: dc})
	}

	return pc, nil
}

func listenWebRTC(config *webrtc.Configuration) (*webRTCListener, error) {
	ln := new(webRTCListener)
	ln.peerConnectionChan = make(chan *webrtc.PeerConnection)
	ln.stopChan = make(chan struct{})

	// This goroutine builds new PeerConnections that await incoming offers.
	go func() {
	loop:
		for {
			select {
			case <-ln.stopChan:
				break loop
			default:
				pc, err := makePeerConnection(config)
				if err != nil {
					log.Printf("makePeerConnection: %s", err)
					break
func readSignalingMessages(signalChan chan *webrtc.SessionDescription, f *os.File) {
	s := bufio.NewScanner(f)
	for s.Scan() {
		msg := s.Text()
		sdp := webrtc.DeserializeSessionDescription(msg)
		if sdp == nil {
			log.Printf("ignoring invalid signal message %q", msg)
			continue
		}
				ln.peerConnectionChan <- pc
		signalChan <- sdp
	}
	if err := s.Err(); err != nil {
		log.Printf("signal FIFO: %s", err)
	}
		close(ln.peerConnectionChan)
	}()

	return ln, nil
}

func handler(conn net.Conn) error {
	defer conn.Close()

	handlerChan <- 1
	defer func() {
		handlerChan <- -1
	}()

	or, err := pt.DialOr(&ptInfo, conn.RemoteAddr().String(), "webrtc")
func generateAnswer(pc *webrtc.PeerConnection) {
	fmt.Println("Generating answer...")
	answer, err := pc.CreateAnswer() // blocking
	if err != nil {
		return err
		fmt.Println(err)
		return
	}
	defer or.Close()

	copyLoop(conn, or)

	return nil
	pc.SetLocalDescription(answer)
}

func acceptLoop(ln net.Listener) error {
	defer ln.Close()
	for {
		conn, err := ln.Accept()
func listenWebRTC(config *webrtc.Configuration, signal string) (*os.File, error) {
	err := syscall.Mkfifo(signal, 0600)
	if err != nil {
			if e, ok := err.(net.Error); ok && e.Temporary() {
				continue
			}
			return err
		if err.(syscall.Errno) != syscall.EEXIST {
			return nil, err
		}
		go handler(conn)
	}
	signalFile, err := os.OpenFile(signal, os.O_RDONLY, 0600)
	if err != nil {
		return nil, err
	}
	defer signalFile.Close()

func readSignalingMessages(f *os.File) {
	s := bufio.NewScanner(f)
	for s.Scan() {
		msg := s.Text()
		sdp := webrtc.DeserializeSessionDescription(msg)
		if sdp == nil {
			log.Printf("ignoring invalid signal message %q", msg)
			continue
	var signalChan = make(chan *webrtc.SessionDescription)

	go func() {
		for {
			select {
			case sdp := <- signalChan:
				pc, err := makePeerConnection(config)
				if err != nil {
					log.Printf("makePeerConnection: %s", err)
					break
				}
		signalChan <- sdp
				err = pc.SetRemoteDescription(sdp)
				if err != nil {
					fmt.Println("ERROR", err)
					break
				}
				fmt.Println("sdp offer successfully received.")
				go generateAnswer(pc)
			}
	close(signalChan)
	if err := s.Err(); err != nil {
		log.Printf("signal FIFO: %s", err)
		}
	}()

	go readSignalingMessages(signalChan, signalFile)
	return signalFile, nil
}

func main() {
	var err error

	logFile, err = os.OpenFile("webrtc-server.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
	logFile, err = os.OpenFile("snowflake.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
	if err != nil {
		log.Fatal(err)
	}
@@ -254,7 +204,6 @@ func main() {
	log.SetOutput(logFile)

	log.Println("starting")

	webrtc.SetLoggingVerbosity(1)

	ptInfo, err = pt.ServerSetup(nil)
@@ -264,18 +213,16 @@ func main() {

	webRTCConfig := webrtc.NewConfiguration(webrtc.OptionIceServer("stun:stun.l.google.com:19302"))

	listeners := make([]net.Listener, 0)
	listeners := make([]*os.File, 0)
	for _, bindaddr := range ptInfo.Bindaddrs {
		switch bindaddr.MethodName {
		case "webrtc":
			// Ignore bindaddr.Addr.
			ln, err := listenWebRTC(webRTCConfig)
		case ptMethodName:
			ln, err := listenWebRTC(webRTCConfig, "signal") // meh
			if err != nil {
				pt.SmethodError(bindaddr.MethodName, err.Error())
				break
			}
			go acceptLoop(ln)
			pt.Smethod(bindaddr.MethodName, ln.Addr())
			pt.Smethod(bindaddr.MethodName, nil)
			listeners = append(listeners, ln)
		default:
			pt.SmethodError(bindaddr.MethodName, "no such method")
+2 −1
Original line number Diff line number Diff line
@@ -3,5 +3,6 @@ ORPort 9001
ExtORPort auto
SocksPort 0
ExitPolicy reject *:*
DataDirectory datadir

ServerTransportPlugin snowflake exec ./snowflake
ServerTransportPlugin snowflake exec ./server