mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-14 05:11:19 -04:00
broker successfully passing client offers to snowflake proxy (#1)
This commit is contained in:
parent
0cd6852ad0
commit
7081e6328c
3 changed files with 75 additions and 46 deletions
|
@ -2,7 +2,7 @@ package snowflake_broker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/heap"
|
"container/heap"
|
||||||
"fmt"
|
// "fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
@ -104,8 +104,8 @@ func clientHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
// TODO: Make this much better.
|
// TODO: Make this much better.
|
||||||
snowflake := heap.Pop(snowflakes).(*Snowflake)
|
snowflake := heap.Pop(snowflakes).(*Snowflake)
|
||||||
if nil == snowflake {
|
if nil == snowflake {
|
||||||
|
// w.Header().Set("Status", http.StatusServiceUnavailable)
|
||||||
w.Write([]byte("no snowflake proxies available"))
|
w.Write([]byte("no snowflake proxies available"))
|
||||||
// w.WriteHeader(http.StatusServiceUnavailable)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// snowflakes = snowflakes[1:]
|
// snowflakes = snowflakes[1:]
|
||||||
|
@ -135,10 +135,11 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Println("Passing client offer to snowflake.")
|
log.Println("Passing client offer to snowflake.")
|
||||||
w.Write(offer)
|
w.Write(offer)
|
||||||
case <-time.After(time.Second * 10):
|
case <-time.After(time.Second * 10):
|
||||||
s := fmt.Sprintf("%d snowflakes left.", snowflakes.Len())
|
// s := fmt.Sprintf("%d snowflakes left.", snowflakes.Len())
|
||||||
w.Write([]byte("timed out. " + s))
|
// w.Write([]byte("timed out. " + s))
|
||||||
|
// w.Header().Set("Status", http.StatusRequestTimeout)
|
||||||
|
w.WriteHeader(http.StatusGatewayTimeout)
|
||||||
heap.Remove(snowflakes, snowflake.index)
|
heap.Remove(snowflakes, snowflake.index)
|
||||||
// w.WriteHeader(http.StatusRequestTimeout)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,43 +5,51 @@ Browser snowflakes must register with the broker in order
|
||||||
to get assigned to clients.
|
to get assigned to clients.
|
||||||
###
|
###
|
||||||
|
|
||||||
|
STATUS_OK = 200
|
||||||
|
STATUS_GATEWAY_TIMEOUT = 504
|
||||||
|
|
||||||
# Represents a broker running remotely.
|
# Represents a broker running remotely.
|
||||||
class Broker
|
class Broker
|
||||||
|
|
||||||
|
clients: 0
|
||||||
|
|
||||||
# When interacting with the Broker, snowflake must generate a unique session
|
# When interacting with the Broker, snowflake must generate a unique session
|
||||||
# ID so the Broker can keep track of which signalling channel it's speaking
|
# ID so the Broker can keep track of which signalling channel it's speaking
|
||||||
# to.
|
# to.
|
||||||
constructor: (@url) ->
|
constructor: (@url) ->
|
||||||
log 'Using Broker at ' + @url
|
log 'Using Broker at ' + @url
|
||||||
|
clients = 0
|
||||||
|
|
||||||
# Snowflake registers with the broker using an HTTP POST request, and expects
|
# Snowflake registers with the broker using an HTTP POST request, and expects
|
||||||
# a response from the broker containing some client offer
|
# a response from the broker containing some client offer.
|
||||||
register: ->
|
# TODO: Actually support multiple clients.
|
||||||
# base_url = this.fac_url.replace(/\?.*/, "");
|
getClientOffer: ->
|
||||||
# url = base_url + "?" + build_query_string(params);
|
new Promise (fulfill, reject) =>
|
||||||
xhr = new XMLHttpRequest()
|
xhr = new XMLHttpRequest()
|
||||||
try
|
try
|
||||||
xhr.open 'POST', @url
|
xhr.open 'POST', @url
|
||||||
catch err
|
catch err
|
||||||
###
|
###
|
||||||
An exception happens here when, for example, NoScript allows the domain on
|
An exception happens here when, for example, NoScript allows the domain
|
||||||
which the proxy badge runs, but not the domain to which it's trying to
|
on which the proxy badge runs, but not the domain to which it's trying
|
||||||
make the HTTP request. The exception message is like "Component returned
|
to make the HTTP request. The exception message is like "Component
|
||||||
failure code: 0x805e0006 [nsIXMLHttpRequest.open]" on Firefox.
|
returned failure code: 0x805e0006 [nsIXMLHttpRequest.open]" on Firefox.
|
||||||
###
|
###
|
||||||
log 'Broker: exception while connecting: ' + err.message
|
log 'Broker: exception while connecting: ' + err.message
|
||||||
return
|
return
|
||||||
|
xhr.onreadystatechange = ->
|
||||||
|
return if xhr.DONE != xhr.readyState
|
||||||
|
switch xhr.status
|
||||||
|
when STATUS_OK
|
||||||
|
fulfill xhr.responseText # Should contain offer.
|
||||||
|
when STATUS_GATEWAY_TIMEOUT
|
||||||
|
reject 'Timed out waiting for a client to serve. Retrying...'
|
||||||
|
else
|
||||||
|
log 'Broker ERROR: Unexpected ' + xhr.status +
|
||||||
|
' - ' + xhr.statusText
|
||||||
|
|
||||||
# xhr.responseType = 'text'
|
xhr.send 'snowflake-testing'
|
||||||
xhr.onreadystatechange = ->
|
log "Broker: polling for client offer..."
|
||||||
if xhr.DONE == xhr.readyState
|
|
||||||
log 'Broker: ' + xhr.status
|
|
||||||
if 200 == xhr.status
|
|
||||||
log 'Response: ' + xhr.responseText
|
|
||||||
log xhr
|
|
||||||
else
|
|
||||||
log 'Broker error ' + xhr.status + ' - ' + xhr.statusText
|
|
||||||
xhr.send 'snowflake-testing'
|
|
||||||
log "Broker: sent a registration message, waiting for reply..."
|
|
||||||
|
|
||||||
sendAnswer: (answer) ->
|
sendAnswer: (answer) ->
|
||||||
log 'Sending answer to broker.'
|
log 'Sending answer to broker.'
|
||||||
|
|
|
@ -9,6 +9,7 @@ this must always act as the answerer.
|
||||||
###
|
###
|
||||||
DEFAULT_WEBSOCKET = '192.81.135.242:9901'
|
DEFAULT_WEBSOCKET = '192.81.135.242:9901'
|
||||||
DEFAULT_BROKER = 'https://snowflake-reg.appspot.com/proxy'
|
DEFAULT_BROKER = 'https://snowflake-reg.appspot.com/proxy'
|
||||||
|
COPY_PASTE_ENABLED = false
|
||||||
DEFAULT_PORTS =
|
DEFAULT_PORTS =
|
||||||
http: 80
|
http: 80
|
||||||
https: 443
|
https: 443
|
||||||
|
@ -58,7 +59,7 @@ class Snowflake
|
||||||
$badge: null
|
$badge: null
|
||||||
state: MODE.INIT
|
state: MODE.INIT
|
||||||
|
|
||||||
constructor: ->
|
constructor: (@broker) ->
|
||||||
if HEADLESS
|
if HEADLESS
|
||||||
# No badge
|
# No badge
|
||||||
else if DEBUG
|
else if DEBUG
|
||||||
|
@ -98,6 +99,27 @@ class Snowflake
|
||||||
@makeProxyPair @relayAddr
|
@makeProxyPair @relayAddr
|
||||||
@proxyPair = @proxyPairs[0]
|
@proxyPair = @proxyPairs[0]
|
||||||
|
|
||||||
|
# Poll broker for clients.
|
||||||
|
findClients: ->
|
||||||
|
poll = =>
|
||||||
|
recv = broker.getClientOffer()
|
||||||
|
recv.then((desc) =>
|
||||||
|
log 'Received:\n\n' + desc + '\n'
|
||||||
|
offer = JSON.parse desc
|
||||||
|
@receiveOffer offer
|
||||||
|
, (err) ->
|
||||||
|
log err
|
||||||
|
setTimeout(poll, 1000)
|
||||||
|
)
|
||||||
|
poll()
|
||||||
|
|
||||||
|
# if @proxyPairs.length >= MAX_NUM_CLIENTS * CONNECTIONS_PER_CLIENT
|
||||||
|
# setTimeout(@proxyMain, @broker_poll_interval * 1000)
|
||||||
|
# return
|
||||||
|
# params = [['r', '1']]
|
||||||
|
# params.push ['transport', 'websocket']
|
||||||
|
# params.push ['transport', 'webrtc']
|
||||||
|
|
||||||
# Receive an SDP offer from client plugin.
|
# Receive an SDP offer from client plugin.
|
||||||
receiveOffer: (desc) =>
|
receiveOffer: (desc) =>
|
||||||
sdp = new RTCSessionDescription desc
|
sdp = new RTCSessionDescription desc
|
||||||
|
@ -117,14 +139,6 @@ class Snowflake
|
||||||
promise = @proxyPair.pc.createAnswer next
|
promise = @proxyPair.pc.createAnswer next
|
||||||
promise.then next if promise
|
promise.then next if promise
|
||||||
|
|
||||||
# Poll broker when this snowflake can support more clients.
|
|
||||||
proxyMain: ->
|
|
||||||
if @proxyPairs.length >= MAX_NUM_CLIENTS * CONNECTIONS_PER_CLIENT
|
|
||||||
setTimeout(@proxyMain, @broker_poll_interval * 1000)
|
|
||||||
return
|
|
||||||
params = [['r', '1']]
|
|
||||||
params.push ['transport', 'websocket']
|
|
||||||
params.push ['transport', 'webrtc']
|
|
||||||
|
|
||||||
makeProxyPair: (relay) ->
|
makeProxyPair: (relay) ->
|
||||||
pair = new ProxyPair null, relay, @rateLimit
|
pair = new ProxyPair null, relay, @rateLimit
|
||||||
|
@ -156,6 +170,7 @@ class Snowflake
|
||||||
@badge.die() if @badge
|
@badge.die() if @badge
|
||||||
|
|
||||||
snowflake = null
|
snowflake = null
|
||||||
|
broker = null
|
||||||
|
|
||||||
#
|
#
|
||||||
## -- DOM & Inputs -- #
|
## -- DOM & Inputs -- #
|
||||||
|
@ -170,7 +185,9 @@ Interface =
|
||||||
# Local input from keyboard into message window.
|
# Local input from keyboard into message window.
|
||||||
acceptInput: ->
|
acceptInput: ->
|
||||||
msg = $input.value
|
msg = $input.value
|
||||||
switch snowflake.state
|
if !COPY_PASTE_ENABLED
|
||||||
|
log 'No input expected - Copy Paste Signalling disabled.'
|
||||||
|
else switch snowflake.state
|
||||||
when MODE.INIT
|
when MODE.INIT
|
||||||
# Set target relay.
|
# Set target relay.
|
||||||
if !(snowflake.setRelayAddr msg)
|
if !(snowflake.setRelayAddr msg)
|
||||||
|
@ -224,10 +241,13 @@ init = ->
|
||||||
$input.onkeydown = (e) -> $send.onclick() if 13 == e.keyCode # enter
|
$input.onkeydown = (e) -> $send.onclick() if 13 == e.keyCode # enter
|
||||||
|
|
||||||
log '== snowflake browser proxy =='
|
log '== snowflake browser proxy =='
|
||||||
snowflake = new Snowflake()
|
|
||||||
window.snowflake = snowflake
|
|
||||||
broker = new Broker DEFAULT_BROKER
|
broker = new Broker DEFAULT_BROKER
|
||||||
broker.register()
|
snowflake = new Snowflake(broker)
|
||||||
log 'Input desired relay address:'
|
window.snowflake = snowflake
|
||||||
|
if COPY_PASTE_ENABLED
|
||||||
|
log 'Input desired relay address:'
|
||||||
|
else
|
||||||
|
snowflake.setRelayAddr DEFAULT_WEBSOCKET
|
||||||
|
snowflake.findClients()
|
||||||
|
|
||||||
window.onload = init if window
|
window.onload = init if window
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue