commit 7081e6328c34db31fec437aabaac829a9280e0f9 Author: Serene Han keroserene+git@gmail.com Date: Thu Jan 21 11:40:42 2016 -0800
broker successfully passing client offers to snowflake proxy (#1) --- broker/snowflake-broker.go | 11 ++++---- proxy/broker.coffee | 64 +++++++++++++++++++++++++------------------- proxy/snowflake.coffee | 48 +++++++++++++++++++++++---------- 3 files changed, 76 insertions(+), 47 deletions(-)
diff --git a/broker/snowflake-broker.go b/broker/snowflake-broker.go index 279b2b6..1d26eb1 100644 --- a/broker/snowflake-broker.go +++ b/broker/snowflake-broker.go @@ -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) } }
diff --git a/proxy/broker.coffee b/proxy/broker.coffee index 9432e5c..688d45d 100644 --- a/proxy/broker.coffee +++ b/proxy/broker.coffee @@ -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); - 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. - ### - 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 - else - log 'Broker error ' + xhr.status + ' - ' + xhr.statusText - xhr.send 'snowflake-testing' - log "Broker: sent a registration message, waiting for reply..." + # 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. + ### + log 'Broker: exception while connecting: ' + err.message + 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.send 'snowflake-testing' + log "Broker: polling for client offer..."
sendAnswer: (answer) -> log 'Sending answer to broker.' diff --git a/proxy/snowflake.coffee b/proxy/snowflake.coffee index 1b837d5..646b9b4 100644 --- a/proxy/snowflake.coffee +++ b/proxy/snowflake.coffee @@ -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() - log 'Input desired relay address:' + 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
tor-commits@lists.torproject.org