mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-14 05:11:19 -04:00
Remove copy/paste signalling
This commit is contained in:
parent
79c84509fc
commit
622005c79e
13 changed files with 18 additions and 283 deletions
25
README.md
25
README.md
|
@ -24,7 +24,6 @@ Pluggable Transport using WebRTC, inspired by Flashproxy.
|
||||||
- [Test Environment](#test-environment)
|
- [Test Environment](#test-environment)
|
||||||
- [FAQ](#faq)
|
- [FAQ](#faq)
|
||||||
- [Appendix](#appendix)
|
- [Appendix](#appendix)
|
||||||
- [-- Testing Copy-Paste Via Browser Proxy --](#---testing-copy-paste-via-browser-proxy---)
|
|
||||||
- [-- Testing directly via WebRTC Server --](#---testing-directly-via-webrtc-server---)
|
- [-- Testing directly via WebRTC Server --](#---testing-directly-via-webrtc-server---)
|
||||||
|
|
||||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
@ -69,9 +68,7 @@ comma-separated list of ICE servers, which are required for NAT traversal.
|
||||||
|
|
||||||
For logging, run `tail -F snowflake.log` in a second terminal.
|
For logging, run `tail -F snowflake.log` in a second terminal.
|
||||||
|
|
||||||
You can modify the `torrc` to use your own broker,
|
You can modify the `torrc` to use your own broker:
|
||||||
or remove the options entirely which will default to the old copy paste
|
|
||||||
method (see `torrc-manual`):
|
|
||||||
|
|
||||||
```
|
```
|
||||||
ClientTransportPlugin snowflake exec ./client --meek
|
ClientTransportPlugin snowflake exec ./client --meek
|
||||||
|
@ -155,26 +152,6 @@ go build
|
||||||
./proxy-go
|
./proxy-go
|
||||||
```
|
```
|
||||||
|
|
||||||
##### -- Testing Copy-Paste Via Browser Proxy --
|
|
||||||
|
|
||||||
Open a browser proxy, passing the `manual` parameter; e.g.
|
|
||||||
`http://127.0.0.1:8000/snowflake.html?manual=1`,
|
|
||||||
|
|
||||||
Open up three terminals for the **client:**
|
|
||||||
|
|
||||||
A: `tor -f torrc-manual SOCKSPort auto`
|
|
||||||
|
|
||||||
B: `cat > signal`
|
|
||||||
|
|
||||||
C: `tail -F snowflake.log`
|
|
||||||
|
|
||||||
Then, in the browser proxy:
|
|
||||||
|
|
||||||
- Look for the offer in terminal C; copy and paste it into the browser.
|
|
||||||
- Copy and paste the answer generated in the browser back to terminal B.
|
|
||||||
- Once WebRTC successfully connects, the browser terminal should turn green.
|
|
||||||
Shortly after, the tor client should bootstrap to 100%.
|
|
||||||
|
|
||||||
##### -- Testing directly via WebRTC Server --
|
##### -- Testing directly via WebRTC Server --
|
||||||
|
|
||||||
See server-webrtc/README.md for information on connecting directly to a
|
See server-webrtc/README.md for information on connecting directly to a
|
||||||
|
|
|
@ -12,12 +12,9 @@ ClientTransportPlugin snowflake exec ./client \
|
||||||
-ice stun:stun.l.google.com:19302
|
-ice stun:stun.l.google.com:19302
|
||||||
```
|
```
|
||||||
|
|
||||||
`-url` should be the URL of a Broker instance. This is required to have
|
`-url` should be the URL of a Broker instance.
|
||||||
automated signalling (which is desired in most use cases).
|
|
||||||
When omitted, the client uses copy-paste signalling instead.
|
|
||||||
|
|
||||||
`-front` is an optional front domain for the Broker request.
|
`-front` is an optional front domain for the Broker request.
|
||||||
|
|
||||||
`-ice` is a comma-separated list of ICE servers. These can be STUN or TURN
|
`-ice` is a comma-separated list of ICE servers. These can be STUN or TURN
|
||||||
servers.
|
servers.
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,20 @@
|
||||||
// WebRTC rendezvous requires the exchange of SessionDescriptions between
|
// WebRTC rendezvous requires the exchange of SessionDescriptions between
|
||||||
// peers in order to establish a PeerConnection.
|
// peers in order to establish a PeerConnection.
|
||||||
//
|
//
|
||||||
// This file contains the two methods currently available to Snowflake:
|
// This file contains the one method currently available to Snowflake:
|
||||||
//
|
//
|
||||||
// - Domain-fronted HTTP signaling. The Broker automatically exchange offers
|
// - Domain-fronted HTTP signaling. The Broker automatically exchange offers
|
||||||
// and answers between this client and some remote WebRTC proxy.
|
// 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 lib
|
package lib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/keroserene/go-webrtc"
|
"github.com/keroserene/go-webrtc"
|
||||||
)
|
)
|
||||||
|
@ -143,71 +137,3 @@ func (w WebRTCDialer) Catch() (Snowflake, error) {
|
||||||
err := connection.Connect()
|
err := connection.Connect()
|
||||||
return connection, err
|
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 *WebRTCPeer
|
|
||||||
}
|
|
||||||
|
|
||||||
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 Peer via manual copy-paste.
|
|
||||||
func (d *CopyPasteDialer) Catch() (Snowflake, error) {
|
|
||||||
if nil == d.signal {
|
|
||||||
return nil, errors.New("Cannot copy-paste dial without signal pipe.")
|
|
||||||
}
|
|
||||||
connection := NewWebRTCPeer(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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -284,14 +284,7 @@ func (c *WebRTCPeer) sendOfferToBroker() {
|
||||||
// the Broker or signal pipe, then await for the SDP answer.
|
// the Broker or signal pipe, then await for the SDP answer.
|
||||||
func (c *WebRTCPeer) exchangeSDP() error {
|
func (c *WebRTCPeer) exchangeSDP() error {
|
||||||
select {
|
select {
|
||||||
case offer := <-c.offerChannel:
|
case <-c.offerChannel:
|
||||||
// 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\n" + offer.Serialize() + "\n\n")
|
|
||||||
log.Printf("----------------")
|
|
||||||
}
|
|
||||||
case err := <-c.errorChannel:
|
case err := <-c.errorChannel:
|
||||||
log.Println("Failed to prepare offer", err)
|
log.Println("Failed to prepare offer", err)
|
||||||
c.Close()
|
c.Close()
|
||||||
|
|
|
@ -113,14 +113,11 @@ func main() {
|
||||||
|
|
||||||
// Prepare to collect remote WebRTC peers.
|
// Prepare to collect remote WebRTC peers.
|
||||||
snowflakes := sf.NewPeers(*max)
|
snowflakes := sf.NewPeers(*max)
|
||||||
if "" != *brokerURL {
|
|
||||||
// Use potentially domain-fronting broker to rendezvous.
|
// Use potentially domain-fronting broker to rendezvous.
|
||||||
broker := sf.NewBrokerChannel(*brokerURL, *frontDomain, sf.CreateBrokerTransport())
|
broker := sf.NewBrokerChannel(*brokerURL, *frontDomain, sf.CreateBrokerTransport())
|
||||||
snowflakes.Tongue = sf.NewWebRTCDialer(broker, iceServers)
|
snowflakes.Tongue = sf.NewWebRTCDialer(broker, iceServers)
|
||||||
} else {
|
|
||||||
// Otherwise, use manual copy and pasting of SDP messages.
|
|
||||||
snowflakes.Tongue = sf.NewCopyPasteDialer(iceServers)
|
|
||||||
}
|
|
||||||
if nil == snowflakes.Tongue {
|
if nil == snowflakes.Tongue {
|
||||||
log.Fatal("Unable to prepare rendezvous method.")
|
log.Fatal("Unable to prepare rendezvous method.")
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
UseBridges 1
|
|
||||||
DataDirectory datadir
|
|
||||||
|
|
||||||
ClientTransportPlugin snowflake exec ./client \
|
|
||||||
-log snowflake.log
|
|
||||||
|
|
||||||
Bridge snowflake 0.0.3.0:1
|
|
|
@ -33,8 +33,3 @@ With no parameters,
|
||||||
snowflake uses the default relay `snowflake.bamsoftware.com:443` and
|
snowflake uses the default relay `snowflake.bamsoftware.com:443` and
|
||||||
uses automatic signaling with the default broker at
|
uses automatic signaling with the default broker at
|
||||||
`https://snowflake-broker.bamsoftware.com/`.
|
`https://snowflake-broker.bamsoftware.com/`.
|
||||||
|
|
||||||
Here are optional parameters to include in the query string.
|
|
||||||
```
|
|
||||||
manual - enables copy-paste signalling mode.
|
|
||||||
```
|
|
||||||
|
|
|
@ -40,15 +40,11 @@ class ProxyPair
|
||||||
] }
|
] }
|
||||||
@pc.onicecandidate = (evt) =>
|
@pc.onicecandidate = (evt) =>
|
||||||
# Browser sends a null candidate once the ICE gathering completes.
|
# Browser sends a null candidate once the ICE gathering completes.
|
||||||
# In this case, it makes sense to send one copy-paste blob.
|
|
||||||
if null == evt.candidate
|
if null == evt.candidate
|
||||||
# TODO: Use a promise.all to tell Snowflake about all offers at once,
|
# TODO: Use a promise.all to tell Snowflake about all offers at once,
|
||||||
# once multiple proxypairs are supported.
|
# once multiple proxypairs are supported.
|
||||||
dbg 'Finished gathering ICE candidates.'
|
dbg 'Finished gathering ICE candidates.'
|
||||||
if COPY_PASTE_ENABLED
|
snowflake.broker.sendAnswer @id, @pc.localDescription
|
||||||
Signalling.send @pc.localDescription
|
|
||||||
else
|
|
||||||
snowflake.broker.sendAnswer @id, @pc.localDescription
|
|
||||||
# OnDataChannel triggered remotely from the client when connection succeeds.
|
# OnDataChannel triggered remotely from the client when connection succeeds.
|
||||||
@pc.ondatachannel = (dc) =>
|
@pc.ondatachannel = (dc) =>
|
||||||
channel = dc.channel
|
channel = dc.channel
|
||||||
|
@ -193,4 +189,3 @@ class ProxyPair
|
||||||
webrtcIsReady: -> null != @client && 'open' == @client.readyState
|
webrtcIsReady: -> null != @client && 'open' == @client.readyState
|
||||||
relayIsReady: -> (null != @relay) && (WebSocket.OPEN == @relay.readyState)
|
relayIsReady: -> (null != @relay) && (WebSocket.OPEN == @relay.readyState)
|
||||||
isClosed: (ws) -> undefined == ws || WebSocket.CLOSED == ws.readyState
|
isClosed: (ws) -> undefined == ws || WebSocket.CLOSED == ws.readyState
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,11 @@ RELAY =
|
||||||
# Original non-wss relay:
|
# Original non-wss relay:
|
||||||
# host: '192.81.135.242'
|
# host: '192.81.135.242'
|
||||||
# port: 9902
|
# port: 9902
|
||||||
COPY_PASTE_ENABLED = false
|
|
||||||
COOKIE_NAME = "snowflake-allow"
|
COOKIE_NAME = "snowflake-allow"
|
||||||
|
|
||||||
silenceNotifications = false
|
silenceNotifications = false
|
||||||
query = Query.parse(location)
|
query = Query.parse(location)
|
||||||
DEBUG = Params.getBool(query, 'debug', false)
|
DEBUG = Params.getBool(query, 'debug', false)
|
||||||
COPY_PASTE_ENABLED = Params.getBool(query, 'manual', false)
|
|
||||||
|
|
||||||
# Bytes per second. Set to undefined to disable limit.
|
# Bytes per second. Set to undefined to disable limit.
|
||||||
DEFAULT_RATE_LIMIT = DEFAULT_RATE_LIMIT || undefined
|
DEFAULT_RATE_LIMIT = DEFAULT_RATE_LIMIT || undefined
|
||||||
|
@ -78,17 +76,14 @@ class Snowflake
|
||||||
setRelayAddr: (relayAddr) ->
|
setRelayAddr: (relayAddr) ->
|
||||||
@relayAddr = relayAddr
|
@relayAddr = relayAddr
|
||||||
log 'Using ' + relayAddr.host + ':' + relayAddr.port + ' as Relay.'
|
log 'Using ' + relayAddr.host + ':' + relayAddr.port + ' as Relay.'
|
||||||
log 'Input offer from the snowflake client:' if COPY_PASTE_ENABLED
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
# Initialize WebRTC PeerConnection, which requires beginning the signalling
|
# Initialize WebRTC PeerConnection, which requires beginning the signalling
|
||||||
# process. If in copy paste mode, the user will need to copy and paste the SDP
|
# process. |pollBroker| automatically arranges signalling.
|
||||||
# blobs. Otherwise, |pollBroker| automatically arranges signalling.
|
|
||||||
beginWebRTC: ->
|
beginWebRTC: ->
|
||||||
@state = MODE.WEBRTC_CONNECTING
|
@state = MODE.WEBRTC_CONNECTING
|
||||||
for i in [1..CONNECTIONS_PER_CLIENT]
|
for i in [1..CONNECTIONS_PER_CLIENT]
|
||||||
@makeProxyPair @relayAddr
|
@makeProxyPair @relayAddr
|
||||||
return if COPY_PASTE_ENABLED
|
|
||||||
log 'ProxyPair Slots: ' + @proxyPairs.length
|
log 'ProxyPair Slots: ' + @proxyPairs.length
|
||||||
log 'Snowflake IDs: ' + (@proxyPairs.map (p) -> p.id).join ' | '
|
log 'Snowflake IDs: ' + (@proxyPairs.map (p) -> p.id).join ' | '
|
||||||
@pollBroker()
|
@pollBroker()
|
||||||
|
@ -182,31 +177,6 @@ class Snowflake
|
||||||
|
|
||||||
snowflake = null
|
snowflake = null
|
||||||
|
|
||||||
# Signalling channel - just tells user to copy paste to the peer.
|
|
||||||
# When copy-paste mode is not enabled, this is handled automatically by Broker.
|
|
||||||
Signalling =
|
|
||||||
send: (msg) ->
|
|
||||||
log '---- Please copy the below to peer ----\n'
|
|
||||||
log JSON.stringify msg
|
|
||||||
log '\n'
|
|
||||||
|
|
||||||
receive: (msg) ->
|
|
||||||
recv = ''
|
|
||||||
try
|
|
||||||
recv = JSON.parse msg
|
|
||||||
catch e
|
|
||||||
log 'Invalid JSON.'
|
|
||||||
return
|
|
||||||
desc = recv['sdp']
|
|
||||||
if !desc
|
|
||||||
log 'Invalid SDP.'
|
|
||||||
return false
|
|
||||||
pair = snowflake.nextAvailableProxyPair()
|
|
||||||
if !pair
|
|
||||||
log 'At client capacity.'
|
|
||||||
return false
|
|
||||||
snowflake.receiveOffer pair, msg
|
|
||||||
|
|
||||||
# Log to both console and UI if applicable.
|
# Log to both console and UI if applicable.
|
||||||
# Requires that the snowflake and UI objects are hooked up in order to
|
# Requires that the snowflake and UI objects are hooked up in order to
|
||||||
# log to console.
|
# log to console.
|
||||||
|
@ -246,8 +216,7 @@ init = (isNode) ->
|
||||||
return
|
return
|
||||||
|
|
||||||
# Otherwise, begin setting up WebRTC and acting as a proxy.
|
# Otherwise, begin setting up WebRTC and acting as a proxy.
|
||||||
log 'Copy-Paste mode detected.' if COPY_PASTE_ENABLED
|
dbg 'Contacting Broker at ' + broker.url
|
||||||
dbg 'Contacting Broker at ' + broker.url if not COPY_PASTE_ENABLED
|
|
||||||
snowflake.setRelayAddr RELAY
|
snowflake.setRelayAddr RELAY
|
||||||
snowflake.beginWebRTC()
|
snowflake.beginWebRTC()
|
||||||
|
|
||||||
|
|
|
@ -10,16 +10,12 @@ describe 'UI', ->
|
||||||
it 'activates debug mode when badge does not exist', ->
|
it 'activates debug mode when badge does not exist', ->
|
||||||
spyOn(document, 'getElementById').and.callFake (id) ->
|
spyOn(document, 'getElementById').and.callFake (id) ->
|
||||||
return null if 'badge' == id
|
return null if 'badge' == id
|
||||||
return {
|
return {}
|
||||||
focus: ->
|
|
||||||
}
|
|
||||||
u = new UI()
|
u = new UI()
|
||||||
expect(u.debug).toBe true
|
expect(u.debug).toBe true
|
||||||
expect(document.getElementById.calls.count()).toEqual 5
|
expect(document.getElementById.calls.count()).toEqual 3
|
||||||
expect(u.$status).not.toBeNull()
|
expect(u.$status).not.toBeNull()
|
||||||
expect(u.$msglog).not.toBeNull()
|
expect(u.$msglog).not.toBeNull()
|
||||||
expect(u.$send).not.toBeNull()
|
|
||||||
expect(u.$input).not.toBeNull()
|
|
||||||
|
|
||||||
it 'is not debug mode when badge exists', ->
|
it 'is not debug mode when badge exists', ->
|
||||||
spyOn(document, 'getElementById').and.callFake (id) ->
|
spyOn(document, 'getElementById').and.callFake (id) ->
|
||||||
|
@ -31,8 +27,6 @@ describe 'UI', ->
|
||||||
expect(document.getElementById.calls.count()).toEqual 1
|
expect(document.getElementById.calls.count()).toEqual 1
|
||||||
expect(u.$status).toBeNull()
|
expect(u.$status).toBeNull()
|
||||||
expect(u.$msglog).toBeNull()
|
expect(u.$msglog).toBeNull()
|
||||||
expect(u.$send).toBeNull()
|
|
||||||
expect(u.$input).toBeNull()
|
|
||||||
|
|
||||||
it 'sets status message only when in debug mode', ->
|
it 'sets status message only when in debug mode', ->
|
||||||
u = new UI()
|
u = new UI()
|
||||||
|
|
|
@ -40,30 +40,6 @@
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
.inputarea {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
height: 3em;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
#input {
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute; left: 0;
|
|
||||||
width: 89%; height: 100%;
|
|
||||||
padding: 8px 30px;
|
|
||||||
font-size: 80%;
|
|
||||||
color: #fff;
|
|
||||||
background-color: rgba(0,0,0,0.9);
|
|
||||||
border: 1px solid #999;
|
|
||||||
}
|
|
||||||
#send {
|
|
||||||
display: inline-block; position: absolute;
|
|
||||||
right: 0; top: 0; height: 100%; width: 10%;
|
|
||||||
background-color: #202; color: #f8f;
|
|
||||||
font-variant: small-caps; font-size: 100%;
|
|
||||||
border: none; /* box-shadow: 0 2px 5px #000; */
|
|
||||||
}
|
|
||||||
#send:hover { background-color: #636; }
|
|
||||||
#status {
|
#status {
|
||||||
background-color: rgba(0,0,0,0.9); color: #999;
|
background-color: rgba(0,0,0,0.9); color: #999;
|
||||||
margin: 8px 0; padding: 8px 1em; cursor: default;
|
margin: 8px 0; padding: 8px 1em; cursor: default;
|
||||||
|
@ -79,10 +55,6 @@
|
||||||
</div>
|
</div>
|
||||||
<textarea id="msglog" readonly>
|
<textarea id="msglog" readonly>
|
||||||
</textarea>
|
</textarea>
|
||||||
<div class="inputarea">
|
|
||||||
<input type="text" id="input">
|
|
||||||
<input type="submit" id="send" value="send">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -7,8 +7,6 @@ class UI
|
||||||
|
|
||||||
# DOM elements references.
|
# DOM elements references.
|
||||||
$msglog: null
|
$msglog: null
|
||||||
$send: null
|
|
||||||
$input: null
|
|
||||||
$status: null
|
$status: null
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
|
@ -21,14 +19,6 @@ class UI
|
||||||
@$msglog = document.getElementById('msglog')
|
@$msglog = document.getElementById('msglog')
|
||||||
@$msglog.value = ''
|
@$msglog.value = ''
|
||||||
|
|
||||||
@$send = document.getElementById('send')
|
|
||||||
@$send.onclick = @acceptInput
|
|
||||||
|
|
||||||
@$input = document.getElementById('input')
|
|
||||||
@$input.focus()
|
|
||||||
@$input.onkeydown = (e) =>
|
|
||||||
@$send.onclick() if 13 == e.keyCode # enter
|
|
||||||
|
|
||||||
# Status bar
|
# Status bar
|
||||||
setStatus: (msg) =>
|
setStatus: (msg) =>
|
||||||
return if !@debug
|
return if !@debug
|
||||||
|
@ -40,21 +30,6 @@ class UI
|
||||||
else
|
else
|
||||||
@$badge.className = if connected then 'active' else ''
|
@$badge.className = if connected then 'active' else ''
|
||||||
|
|
||||||
# Local input from keyboard into message window.
|
|
||||||
acceptInput: =>
|
|
||||||
msg = @$input.value
|
|
||||||
if !COPY_PASTE_ENABLED
|
|
||||||
@log 'No input expected - Copy Paste Signalling disabled.'
|
|
||||||
else switch snowflake.state
|
|
||||||
when MODE.WEBRTC_CONNECTING
|
|
||||||
Signalling.receive msg
|
|
||||||
when MODE.WEBRTC_READY
|
|
||||||
@log 'No input expected - WebRTC connected.'
|
|
||||||
else
|
|
||||||
@log 'ERROR: ' + msg
|
|
||||||
@$input.value = ''
|
|
||||||
@$input.focus()
|
|
||||||
|
|
||||||
log: (msg) =>
|
log: (msg) =>
|
||||||
return if !@debug
|
return if !@debug
|
||||||
# Scroll to latest
|
# Scroll to latest
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -194,43 +193,6 @@ func makePeerConnectionFromOffer(sdp *webrtc.SessionDescription, config *webrtc.
|
||||||
return pc, nil
|
return pc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a signaling named pipe and feed offers from it into
|
|
||||||
// makePeerConnectionFromOffer.
|
|
||||||
func receiveSignalsFIFO(filename string, config *webrtc.Configuration) error {
|
|
||||||
err := syscall.Mkfifo(filename, 0600)
|
|
||||||
if err != nil {
|
|
||||||
if err.(syscall.Errno) != syscall.EEXIST {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
signalFile, err := os.OpenFile(filename, os.O_RDONLY, 0600)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer signalFile.Close()
|
|
||||||
|
|
||||||
s := bufio.NewScanner(signalFile)
|
|
||||||
for s.Scan() {
|
|
||||||
msg := s.Text()
|
|
||||||
sdp := webrtc.DeserializeSessionDescription(msg)
|
|
||||||
if sdp == nil {
|
|
||||||
log.Printf("ignoring invalid signal message %+q", msg)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
pc, err := makePeerConnectionFromOffer(sdp, config)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("makePeerConnectionFromOffer: %s", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Write offer to log for manual signaling.
|
|
||||||
log.Printf("----------------")
|
|
||||||
fmt.Fprintln(logFile, pc.LocalDescription().Serialize())
|
|
||||||
log.Printf("----------------")
|
|
||||||
}
|
|
||||||
return s.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var err error
|
var err error
|
||||||
var httpAddr string
|
var httpAddr string
|
||||||
|
@ -260,24 +222,14 @@ func main() {
|
||||||
|
|
||||||
webRTCConfig := webrtc.NewConfiguration(webrtc.OptionIceServer("stun:stun.l.google.com:19302"))
|
webRTCConfig := webrtc.NewConfiguration(webrtc.OptionIceServer("stun:stun.l.google.com:19302"))
|
||||||
|
|
||||||
// Start FIFO-based signaling receiver.
|
// Start HTTP-based signaling receiver.
|
||||||
go func() {
|
go func() {
|
||||||
err := receiveSignalsFIFO("signal", webRTCConfig)
|
err := receiveSignalsHTTP(httpAddr, webRTCConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("receiveSignalsFIFO: %s", err)
|
log.Printf("receiveSignalsHTTP: %s", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Start HTTP-based signaling receiver.
|
|
||||||
if httpAddr != "" {
|
|
||||||
go func() {
|
|
||||||
err := receiveSignalsHTTP(httpAddr, webRTCConfig)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("receiveSignalsHTTP: %s", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, bindaddr := range ptInfo.Bindaddrs {
|
for _, bindaddr := range ptInfo.Bindaddrs {
|
||||||
switch bindaddr.MethodName {
|
switch bindaddr.MethodName {
|
||||||
case ptMethodName:
|
case ptMethodName:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue