mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-13 20: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 (
|
||||
"container/heap"
|
||||
"fmt"
|
||||
// "fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
|
@ -104,8 +104,8 @@ func clientHandler(w http.ResponseWriter, r *http.Request) {
|
|||
// TODO: Make this much better.
|
||||
snowflake := heap.Pop(snowflakes).(*Snowflake)
|
||||
if nil == snowflake {
|
||||
// w.Header().Set("Status", http.StatusServiceUnavailable)
|
||||
w.Write([]byte("no snowflake proxies available"))
|
||||
// w.WriteHeader(http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
// snowflakes = snowflakes[1:]
|
||||
|
@ -135,10 +135,11 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) {
|
|||
log.Println("Passing client offer to snowflake.")
|
||||
w.Write(offer)
|
||||
case <-time.After(time.Second * 10):
|
||||
s := fmt.Sprintf("%d snowflakes left.", snowflakes.Len())
|
||||
w.Write([]byte("timed out. " + s))
|
||||
// s := fmt.Sprintf("%d snowflakes left.", snowflakes.Len())
|
||||
// w.Write([]byte("timed out. " + s))
|
||||
// w.Header().Set("Status", http.StatusRequestTimeout)
|
||||
w.WriteHeader(http.StatusGatewayTimeout)
|
||||
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.
|
||||
###
|
||||
|
||||
STATUS_OK = 200
|
||||
STATUS_GATEWAY_TIMEOUT = 504
|
||||
|
||||
# Represents a broker running remotely.
|
||||
class Broker
|
||||
|
||||
clients: 0
|
||||
|
||||
# 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
|
||||
# to.
|
||||
constructor: (@url) ->
|
||||
log 'Using Broker at ' + @url
|
||||
clients = 0
|
||||
|
||||
# Snowflake registers with the broker using an HTTP POST request, and expects
|
||||
# a response from the broker containing some client offer
|
||||
register: ->
|
||||
# base_url = this.fac_url.replace(/\?.*/, "");
|
||||
# url = base_url + "?" + build_query_string(params);
|
||||
# a response from the broker containing some client offer.
|
||||
# TODO: Actually support multiple clients.
|
||||
getClientOffer: ->
|
||||
new Promise (fulfill, reject) =>
|
||||
xhr = new XMLHttpRequest()
|
||||
try
|
||||
xhr.open 'POST', @url
|
||||
catch err
|
||||
###
|
||||
An exception happens here when, for example, NoScript allows the domain on
|
||||
which the proxy badge runs, but not the domain to which it's trying to
|
||||
make the HTTP request. The exception message is like "Component returned
|
||||
failure code: 0x805e0006 [nsIXMLHttpRequest.open]" on Firefox.
|
||||
An exception happens here when, for example, NoScript allows the domain
|
||||
on which the proxy badge runs, but not the domain to which it's trying
|
||||
to make the HTTP request. The exception message is like "Component
|
||||
returned failure code: 0x805e0006 [nsIXMLHttpRequest.open]" on Firefox.
|
||||
###
|
||||
log 'Broker: exception while connecting: ' + err.message
|
||||
return
|
||||
|
||||
# xhr.responseType = 'text'
|
||||
xhr.onreadystatechange = ->
|
||||
if xhr.DONE == xhr.readyState
|
||||
log 'Broker: ' + xhr.status
|
||||
if 200 == xhr.status
|
||||
log 'Response: ' + xhr.responseText
|
||||
log xhr
|
||||
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 ' + xhr.status + ' - ' + xhr.statusText
|
||||
log 'Broker ERROR: Unexpected ' + xhr.status +
|
||||
' - ' + xhr.statusText
|
||||
|
||||
xhr.send 'snowflake-testing'
|
||||
log "Broker: sent a registration message, waiting for reply..."
|
||||
log "Broker: polling for client offer..."
|
||||
|
||||
sendAnswer: (answer) ->
|
||||
log 'Sending answer to broker.'
|
||||
|
|
|
@ -9,6 +9,7 @@ this must always act as the answerer.
|
|||
###
|
||||
DEFAULT_WEBSOCKET = '192.81.135.242:9901'
|
||||
DEFAULT_BROKER = 'https://snowflake-reg.appspot.com/proxy'
|
||||
COPY_PASTE_ENABLED = false
|
||||
DEFAULT_PORTS =
|
||||
http: 80
|
||||
https: 443
|
||||
|
@ -58,7 +59,7 @@ class Snowflake
|
|||
$badge: null
|
||||
state: MODE.INIT
|
||||
|
||||
constructor: ->
|
||||
constructor: (@broker) ->
|
||||
if HEADLESS
|
||||
# No badge
|
||||
else if DEBUG
|
||||
|
@ -98,6 +99,27 @@ class Snowflake
|
|||
@makeProxyPair @relayAddr
|
||||
@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.
|
||||
receiveOffer: (desc) =>
|
||||
sdp = new RTCSessionDescription desc
|
||||
|
@ -117,14 +139,6 @@ class Snowflake
|
|||
promise = @proxyPair.pc.createAnswer next
|
||||
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) ->
|
||||
pair = new ProxyPair null, relay, @rateLimit
|
||||
|
@ -156,6 +170,7 @@ class Snowflake
|
|||
@badge.die() if @badge
|
||||
|
||||
snowflake = null
|
||||
broker = null
|
||||
|
||||
#
|
||||
## -- DOM & Inputs -- #
|
||||
|
@ -170,7 +185,9 @@ Interface =
|
|||
# Local input from keyboard into message window.
|
||||
acceptInput: ->
|
||||
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
|
||||
# Set target relay.
|
||||
if !(snowflake.setRelayAddr msg)
|
||||
|
@ -224,10 +241,13 @@ init = ->
|
|||
$input.onkeydown = (e) -> $send.onclick() if 13 == e.keyCode # enter
|
||||
|
||||
log '== snowflake browser proxy =='
|
||||
snowflake = new Snowflake()
|
||||
window.snowflake = snowflake
|
||||
broker = new Broker DEFAULT_BROKER
|
||||
broker.register()
|
||||
snowflake = new Snowflake(broker)
|
||||
window.snowflake = snowflake
|
||||
if COPY_PASTE_ENABLED
|
||||
log 'Input desired relay address:'
|
||||
else
|
||||
snowflake.setRelayAddr DEFAULT_WEBSOCKET
|
||||
snowflake.findClients()
|
||||
|
||||
window.onload = init if window
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue