[tor-commits] [snowflake/master] per-proxypair Snowflake ID generation instead of just one for the Broker (#11)

arlo at torproject.org arlo at torproject.org
Fri Mar 18 17:48:36 UTC 2016


commit b1e76420bd7c3838d128407c9822b089c0296bc2
Author: Serene Han <keroserene+git at gmail.com>
Date:   Mon Mar 14 22:12:28 2016 -0700

    per-proxypair Snowflake ID generation instead of just one for the Broker (#11)
---
 proxy/broker.coffee           | 19 +++++++------------
 proxy/proxypair.coffee        |  8 ++++++--
 proxy/snowflake.coffee        | 30 ++++++++++++++++++++++++------
 proxy/spec/broker.spec.coffee |  6 +++---
 proxy/util.coffee             |  4 ++++
 5 files changed, 44 insertions(+), 23 deletions(-)

diff --git a/proxy/broker.coffee b/proxy/broker.coffee
index 78577e7..9eb378c 100644
--- a/proxy/broker.coffee
+++ b/proxy/broker.coffee
@@ -12,21 +12,16 @@ STATUS_GATEWAY_TIMEOUT = 504
 MESSAGE_TIMEOUT = 'Timed out waiting for a client offer.'
 MESSAGE_UNEXPECTED = 'Unexpected status.'
 
-genSnowflakeID = ->
-  Math.random().toString(36).substring(2)
-
 # Represents a broker running remotely.
 class Broker
 
   clients: 0
-  id: null
 
   # 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) ->
     @clients = 0
-    @id = genSnowflakeID()
     # Ensure url has the right protocol + trailing slash.
     @url = 'http://' + @url if 0 == @url.indexOf('localhost', 0)
     @url = 'https://' + @url if 0 != @url.indexOf('http', 0)
@@ -37,7 +32,7 @@ class Broker
   # waits for a response containing some client offer that the Broker chooses
   # for this proxy..
   # TODO: Actually support multiple clients.
-  getClientOffer: =>
+  getClientOffer: (id) =>
     new Promise (fulfill, reject) =>
       xhr = new XMLHttpRequest()
       xhr.onreadystatechange = ->
@@ -53,12 +48,12 @@ class Broker
             snowflake.ui.setStatus ' failure. Please refresh.'
             reject MESSAGE_UNEXPECTED
       @_xhr = xhr  # Used by spec to fake async Broker interaction
-      @_postRequest xhr, 'proxy', @id
+      @_postRequest id, xhr, 'proxy', id
 
   # Assumes getClientOffer happened, and a WebRTC SDP answer has been generated.
   # Sends it back to the broker, which passes it to back to the original client.
-  sendAnswer: (answer) ->
-    dbg @id + ' - Sending answer back to broker...\n'
+  sendAnswer: (id, answer) ->
+    dbg id + ' - Sending answer back to broker...\n'
     dbg answer.sdp
     xhr = new XMLHttpRequest()
     xhr.onreadystatechange = ->
@@ -73,14 +68,14 @@ class Broker
           dbg 'Broker ERROR: Unexpected ' + xhr.status +
               ' - ' + xhr.statusText
           snowflake.ui.setStatus ' failure. Please refresh.'
-    @_postRequest xhr, 'answer', JSON.stringify(answer)
+    @_postRequest id, xhr, 'answer', JSON.stringify(answer)
 
   # urlSuffix for the broker is different depending on what action
   # is desired.
-  _postRequest: (xhr, urlSuffix, payload) =>
+  _postRequest: (id, xhr, urlSuffix, payload) =>
     try
       xhr.open 'POST', @url + urlSuffix
-      xhr.setRequestHeader('X-Session-ID', @id)
+      xhr.setRequestHeader('X-Session-ID', id)
     catch err
       ###
       An exception happens here when, for example, NoScript allows the domain
diff --git a/proxy/proxypair.coffee b/proxy/proxypair.coffee
index db53612..3a3fb01 100644
--- a/proxy/proxypair.coffee
+++ b/proxy/proxypair.coffee
@@ -3,6 +3,8 @@ Represents a single:
 
    client <-- webrtc --> snowflake <-- websocket --> relay
 
+Every ProxyPair has a Snowflake ID, which is necessary when responding to the
+Broker with an WebRTC answer.
 ###
 
 class ProxyPair
@@ -16,10 +18,12 @@ class ProxyPair
   running:     true
   active:      false  # Whether serving a client.
   flush_timeout_id: null
-  onCleanup:  null
+  onCleanup:   null
+  id:          null
 
   constructor: (@clientAddr, @relayAddr, @rateLimit) ->
     @active = false
+    @id = genSnowflakeID()
 
   # Prepare a WebRTC PeerConnection and await for an SDP offer.
   begin: ->
@@ -38,7 +42,7 @@ class ProxyPair
         if COPY_PASTE_ENABLED
           Signalling.send @pc.localDescription
         else
-          snowflake.broker.sendAnswer @pc.localDescription
+          snowflake.broker.sendAnswer @id, @pc.localDescription
     # OnDataChannel triggered remotely from the client when connection succeeds.
     @pc.ondatachannel = (dc) =>
       channel = dc.channel
diff --git a/proxy/snowflake.coffee b/proxy/snowflake.coffee
index e8c00aa..7cc01c9 100644
--- a/proxy/snowflake.coffee
+++ b/proxy/snowflake.coffee
@@ -84,6 +84,9 @@ class Snowflake
     for i in [1..CONNECTIONS_PER_CLIENT]
       @makeProxyPair @relayAddr
     return if COPY_PASTE_ENABLED
+    log 'ProxyPair Slots: ' + @proxyPairs.length
+    log 'Snowflake IDs: ' + (@proxyPairs.map (p) -> p.id).join ' | '
+
     timer = null
     # Temporary countdown.
     countdown = (msg, sec) =>
@@ -99,22 +102,37 @@ class Snowflake
       msg = 'polling for client... '
       msg += '[retries: ' + @retries + ']' if @retries > 0
       @ui.setStatus msg
-      recv = @broker.getClientOffer()
-      @retries++
+      # Pick an available ProxyPair to poll with.
+      pair = @nextAvailableProxyPair()
+      if !pair
+        log 'No more available ProxyPair slots.'
+        countdown(err, DEFAULT_BROKER_POLL_INTERVAL / 1000)
+        return
+      log 'Polling for ' + pair.id
+      recv = @broker.getClientOffer pair.id
       recv.then (desc) =>
         offer = JSON.parse desc
         dbg 'Received:\n\n' + offer.sdp + '\n'
-        @receiveOffer offer
+        console.log desc
+        sdp = new RTCSessionDescription offer
+        # @receiveOffer offer
+        if pair.receiveWebRTCOffer sdp
+          @sendAnswer pair if 'offer' == sdp.type
       , (err) ->
         countdown(err, DEFAULT_BROKER_POLL_INTERVAL / 1000)
+      @retries++
 
     findClients()
 
+  # Returns the first ProxyPair that's available to connect.
+  nextAvailableProxyPair: ->
+    return @proxyPairs.find (pp, i, arr) -> return !pp.active
+
   # Receive an SDP offer from some client assigned by the Broker,
+  # TODO: remove
   receiveOffer: (desc) =>
     sdp = new RTCSessionDescription desc
-    # Use the first proxyPair that's available.
-    pair = @proxyPairs.find (pp, i, arr) -> return !pp.active
+    pair = @nextAvailableProxyPair()
     if pair.receiveWebRTCOffer sdp
       @sendAnswer pair if 'offer' == sdp.type
 
@@ -190,7 +208,7 @@ init = ->
   broker = new Broker brokerUrl
   snowflake = new Snowflake broker, ui
 
-  dbg 'Contacting Broker at ' + broker.url + '\nSnowflake ID: ' + broker.id
+  dbg 'Contacting Broker at ' + broker.url
   log '== snowflake proxy =='
   log 'Copy-Paste mode detected.' if COPY_PASTE_ENABLED
 
diff --git a/proxy/spec/broker.spec.coffee b/proxy/spec/broker.spec.coffee
index db936c1..aef115f 100644
--- a/proxy/spec/broker.spec.coffee
+++ b/proxy/spec/broker.spec.coffee
@@ -76,9 +76,9 @@ describe 'Broker', ->
   it 'responds to the broker with answer', ->
     b = new Broker 'fake'
     spyOn(b, '_postRequest')
-    b.sendAnswer 123
+    b.sendAnswer 'fake id', 123
     expect(b._postRequest).toHaveBeenCalledWith(
-      jasmine.any(Object), 'answer', '123')
+      'fake id', jasmine.any(Object), 'answer', '123')
 
   it 'POST XMLHttpRequests to the broker', ->
     b = new Broker 'fake'
@@ -86,7 +86,7 @@ describe 'Broker', ->
     spyOn(b._xhr, 'open')
     spyOn(b._xhr, 'setRequestHeader')
     spyOn(b._xhr, 'send')
-    b._postRequest b._xhr, 'test', 'data'
+    b._postRequest 0, b._xhr, 'test', 'data'
     expect(b._xhr.open).toHaveBeenCalled()
     expect(b._xhr.setRequestHeader).toHaveBeenCalled()
     expect(b._xhr.send).toHaveBeenCalled()
diff --git a/proxy/util.coffee b/proxy/util.coffee
index ea65e63..a5b247c 100644
--- a/proxy/util.coffee
+++ b/proxy/util.coffee
@@ -5,6 +5,10 @@ Contains helpers for parsing query strings and other utilities.
 ###
 
 
+genSnowflakeID = ->
+  Math.random().toString(36).substring(2)
+
+
 Query =
   ###
   Parse a URL query string or application/x-www-form-urlencoded body. The





More information about the tor-commits mailing list