From af583b62293083618e930dfa7d6ef6ac661f5af6 Mon Sep 17 00:00:00 2001 From: Cecylia Bocovich Date: Wed, 15 Jan 2020 15:55:22 -0500 Subject: [PATCH 1/8] Set up a throughput test on startup This will contact a (for now hardcoded) probe point to perform a throughput test of the proxy before it polls the broker. For now we just perform a poll of the probe point to receive their WebRTC offer. --- proxy-go/snowflake.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/proxy-go/snowflake.go b/proxy-go/snowflake.go index 5e56842..8315e6b 100644 --- a/proxy-go/snowflake.go +++ b/proxy-go/snowflake.go @@ -403,6 +403,45 @@ func runSession(sid string) { } } +func testThroughput() { + var err error + probe := new(Broker) + probe.transport = http.DefaultTransport.(*http.Transport) + probe.url, err = url.Parse("159.203.63.110") //hard code this for now + if err != nil { + log.Fatalf("invalid probe url: %s", err) + } + brokerPath := probe.url.ResolveReference(&url.URL{Scheme: "http", Host: "159.203.63.110:8080", Path: "api/snowflake-poll"}) + + sessionID := genSessionID() + + req, err := http.NewRequest("POST", brokerPath.String(), bytes.NewBuffer(createSnowflakeRequest(sessionID))) + if err != nil { + log.Printf("Error creating request: %s", err.Error()) + return + } + resp, err := probe.transport.RoundTrip(req) + if err != nil { + log.Printf("error polling broker: %s", err) + } else { + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + log.Printf("proxy returns: %d", resp.StatusCode) + } else { + var offer SnowflakeOffer + decoder := json.NewDecoder(resp.Body) + if err = decoder.Decode(&offer); err != nil { + log.Printf("error reading broker response: %s", err.Error()) + log.Printf("body: %s", resp.Body) + return + } + + log.Printf("offer:%s", offer) + } + } + +} + func main() { var capacity uint var stunURL string @@ -459,6 +498,9 @@ func main() { tokens <- true } + //Perform a throughput test + testThroughput() + for { getToken() sessionID := genSessionID() From e32a69075c92065d1c9d35c7becfc9115e23ae27 Mon Sep 17 00:00:00 2001 From: Cecylia Bocovich Date: Wed, 15 Jan 2020 16:27:00 -0500 Subject: [PATCH 2/8] Create an answer for the throughput test --- proxy-go/snowflake.go | 20 ++++++++++++++++---- proxy-go/throughput.go | 22 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 proxy-go/throughput.go diff --git a/proxy-go/snowflake.go b/proxy-go/snowflake.go index 8315e6b..7506b35 100644 --- a/proxy-go/snowflake.go +++ b/proxy-go/snowflake.go @@ -403,8 +403,10 @@ func runSession(sid string) { } } -func testThroughput() { +func testThroughput(config webrtc.Configuration) { var err error + var offer SnowflakeOffer + probe := new(Broker) probe.transport = http.DefaultTransport.(*http.Transport) probe.url, err = url.Parse("159.203.63.110") //hard code this for now @@ -415,7 +417,7 @@ func testThroughput() { sessionID := genSessionID() - req, err := http.NewRequest("POST", brokerPath.String(), bytes.NewBuffer(createSnowflakeRequest(sessionID))) + req, err := http.NewRequest("POST", brokerPath.String(), bytes.NewBuffer(CreateSnowflakeRequest(sessionID))) if err != nil { log.Printf("Error creating request: %s", err.Error()) return @@ -428,7 +430,6 @@ func testThroughput() { if resp.StatusCode != http.StatusOK { log.Printf("proxy returns: %d", resp.StatusCode) } else { - var offer SnowflakeOffer decoder := json.NewDecoder(resp.Body) if err = decoder.Decode(&offer); err != nil { log.Printf("error reading broker response: %s", err.Error()) @@ -440,6 +441,17 @@ func testThroughput() { } } + sdp := deserializeSessionDescription(offer.Offer) + + // create answer + dataChan := make(chan struct{}) + _, err = makePeerConnectionFromOffer(sdp, config, dataChan) + if err != nil { + log.Printf("error making WebRTC connection: %s", err) + retToken() + return + } + } func main() { @@ -499,7 +511,7 @@ func main() { } //Perform a throughput test - testThroughput() + testThroughput(config) for { getToken() diff --git a/proxy-go/throughput.go b/proxy-go/throughput.go new file mode 100644 index 0000000..725405a --- /dev/null +++ b/proxy-go/throughput.go @@ -0,0 +1,22 @@ +package main + +import ( + "encoding/json" +) + +type SnowflakeRequest struct { + SnowflakeID string `json:"snowflake_id"` +} + +type SnowflakeOffer struct { + Offer string `json:"offer"` +} + +func CreateSnowflakeRequest(id string) []byte { + request := &SnowflakeRequest{ + SnowflakeID: id, + } + jsonRequest, _ := json.Marshal(request) + + return jsonRequest +} From 99826cbe518493e6232f162d468a6f6dd0d8b693 Mon Sep 17 00:00:00 2001 From: Cecylia Bocovich Date: Thu, 16 Jan 2020 11:58:11 -0500 Subject: [PATCH 3/8] Send throughput test answer to probe point Send an SDP answer to the remote probe point and recieve the test results. For now we just log results. --- proxy-go/snowflake.go | 32 +++++++++++++++++++++++++++++++- proxy-go/throughput.go | 21 +++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/proxy-go/snowflake.go b/proxy-go/snowflake.go index 7506b35..945425c 100644 --- a/proxy-go/snowflake.go +++ b/proxy-go/snowflake.go @@ -406,6 +406,7 @@ func runSession(sid string) { func testThroughput(config webrtc.Configuration) { var err error var offer SnowflakeOffer + var result SnowflakeResult probe := new(Broker) probe.transport = http.DefaultTransport.(*http.Transport) @@ -445,13 +446,42 @@ func testThroughput(config webrtc.Configuration) { // create answer dataChan := make(chan struct{}) - _, err = makePeerConnectionFromOffer(sdp, config, dataChan) + pc, err := makePeerConnectionFromOffer(sdp, config, dataChan) if err != nil { log.Printf("error making WebRTC connection: %s", err) retToken() return } + answer := pc.LocalDescription() + + // send answer + testReq := CreateSnowflakeAnswer(sessionID, serializeSessionDescription(answer)) + brokerPath = probe.url.ResolveReference(&url.URL{Scheme: "http", Host: "159.203.63.110:8080", Path: "api/snowflake-test"}) + req, err = http.NewRequest("POST", brokerPath.String(), bytes.NewBuffer(testReq)) + if err != nil { + log.Printf("Error creating request: %s", err.Error()) + return + } + resp, err = probe.transport.RoundTrip(req) + if err != nil { + log.Printf("error polling broker: %s", err) + } else { + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + log.Printf("proxy returns: %d", resp.StatusCode) + } else { + decoder := json.NewDecoder(resp.Body) + if err = decoder.Decode(&result); err != nil { + log.Printf("error reading broker response: %s", err.Error()) + log.Printf("body: %s", resp.Body) + return + } + + log.Printf("offer:%s", result) + } + } + } func main() { diff --git a/proxy-go/throughput.go b/proxy-go/throughput.go index 725405a..9e5e274 100644 --- a/proxy-go/throughput.go +++ b/proxy-go/throughput.go @@ -12,6 +12,17 @@ type SnowflakeOffer struct { Offer string `json:"offer"` } +type SnowflakeAnswer struct { + SnowflakeID string `json:"snowflake_id"` + Answer string `json:"answer"` +} + +type SnowflakeResult struct { + Throughput string `json:"throughput"` + Latency string `json:"latency"` + Error string `json:"error"` +} + func CreateSnowflakeRequest(id string) []byte { request := &SnowflakeRequest{ SnowflakeID: id, @@ -20,3 +31,13 @@ func CreateSnowflakeRequest(id string) []byte { return jsonRequest } + +func CreateSnowflakeAnswer(id string, answer string) []byte { + request := &SnowflakeAnswer{ + SnowflakeID: id, + Answer: answer, + } + jsonRequest, _ := json.Marshal(request) + + return jsonRequest +} From 9c81a672bd4ec82daa5a25a2a95f7af01ed6fe11 Mon Sep 17 00:00:00 2001 From: Cecylia Bocovich Date: Wed, 29 Jan 2020 11:14:38 -0500 Subject: [PATCH 4/8] Refactor to make code reuse easier This refactors makePeerConnectionFromOffer to take a datachannel handler as an argument. This will allow us to reuse this function when conducting the throughput test. --- proxy-go/snowflake.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/proxy-go/snowflake.go b/proxy-go/snowflake.go index 945425c..bc2ffc5 100644 --- a/proxy-go/snowflake.go +++ b/proxy-go/snowflake.go @@ -258,7 +258,7 @@ func CopyLoop(c1 io.ReadWriteCloser, c2 io.ReadWriteCloser) { // conn.RemoteAddr() inside this function, as a workaround for a hang that // otherwise occurs inside of conn.pc.RemoteDescription() (called by // RemoteAddr). https://bugs.torproject.org/18628#comment:8 -func datachannelHandler(conn *webRTCConn, remoteAddr net.Addr) { +func datachannelHandler(conn *webRTCConn) { defer conn.Close() defer retToken() @@ -268,10 +268,10 @@ func datachannelHandler(conn *webRTCConn, remoteAddr net.Addr) { } // Retrieve client IP address - if remoteAddr != nil { + if conn.RemoteAddr() != nil { // Encode client IP address in relay URL q := u.Query() - clientIP := remoteAddr.String() + clientIP := conn.RemoteAddr().String() q.Set("client_ip", clientIP) u.RawQuery = q.Encode() } else { @@ -294,7 +294,10 @@ func datachannelHandler(conn *webRTCConn, remoteAddr net.Addr) { // candidates is complete and the answer is available in LocalDescription. // Installs an OnDataChannel callback that creates a webRTCConn and passes it to // datachannelHandler. -func makePeerConnectionFromOffer(sdp *webrtc.SessionDescription, config webrtc.Configuration, dataChan chan struct{}) (*webrtc.PeerConnection, error) { +func makePeerConnectionFromOffer(sdp *webrtc.SessionDescription, + config webrtc.Configuration, dataChan chan struct{}, + handler func(conn *webRTCConn)) (*webrtc.PeerConnection, error) { + pc, err := webrtc.NewPeerConnection(config) if err != nil { return nil, fmt.Errorf("accept: NewPeerConnection: %s", err) @@ -330,7 +333,7 @@ func makePeerConnectionFromOffer(sdp *webrtc.SessionDescription, config webrtc.C } }) - go datachannelHandler(conn, conn.RemoteAddr()) + go handler(conn) }) err = pc.SetRemoteDescription(*sdp) @@ -373,7 +376,7 @@ func runSession(sid string) { return } dataChan := make(chan struct{}) - pc, err := makePeerConnectionFromOffer(offer, config, dataChan) + pc, err := makePeerConnectionFromOffer(offer, config, dataChan, datachannelHandler) if err != nil { log.Printf("error making WebRTC connection: %s", err) retToken() @@ -446,7 +449,7 @@ func testThroughput(config webrtc.Configuration) { // create answer dataChan := make(chan struct{}) - pc, err := makePeerConnectionFromOffer(sdp, config, dataChan) + pc, err := makePeerConnectionFromOffer(sdp, config, dataChan, datachannelHandler) if err != nil { log.Printf("error making WebRTC connection: %s", err) retToken() From 2d7aa681b8c762d1184e674cb46a57a85eb2f056 Mon Sep 17 00:00:00 2001 From: Cecylia Bocovich Date: Wed, 29 Jan 2020 15:17:33 -0500 Subject: [PATCH 5/8] Make a simple handler for throughput tests --- proxy-go/snowflake.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/proxy-go/snowflake.go b/proxy-go/snowflake.go index bc2ffc5..e9b9955 100644 --- a/proxy-go/snowflake.go +++ b/proxy-go/snowflake.go @@ -406,6 +406,15 @@ func runSession(sid string) { } } +func throughputHandler(conn *webRTCConn) { + defer conn.Close() + + if _, err := io.Copy(conn, conn); err != nil { + log.Printf("io.Copy inside CopyLoop generated an error: %v", err) + } + +} + func testThroughput(config webrtc.Configuration) { var err error var offer SnowflakeOffer @@ -449,7 +458,7 @@ func testThroughput(config webrtc.Configuration) { // create answer dataChan := make(chan struct{}) - pc, err := makePeerConnectionFromOffer(sdp, config, dataChan, datachannelHandler) + pc, err := makePeerConnectionFromOffer(sdp, config, dataChan, throughputHandler) if err != nil { log.Printf("error making WebRTC connection: %s", err) retToken() From f8e6a75274e4292cc786877a7930c01af739149e Mon Sep 17 00:00:00 2001 From: Cecylia Bocovich Date: Thu, 27 Feb 2020 10:17:45 -0500 Subject: [PATCH 6/8] Fix error in SnowflakeResult and clean up prints --- proxy-go/snowflake.go | 7 ++++--- proxy-go/throughput.go | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/proxy-go/snowflake.go b/proxy-go/snowflake.go index e9b9955..e4c34e9 100644 --- a/proxy-go/snowflake.go +++ b/proxy-go/snowflake.go @@ -445,7 +445,7 @@ func testThroughput(config webrtc.Configuration) { } else { decoder := json.NewDecoder(resp.Body) if err = decoder.Decode(&offer); err != nil { - log.Printf("error reading broker response: %s", err.Error()) + log.Printf("error reading bridgestrap response: %s", err.Error()) log.Printf("body: %s", resp.Body) return } @@ -485,12 +485,13 @@ func testThroughput(config webrtc.Configuration) { } else { decoder := json.NewDecoder(resp.Body) if err = decoder.Decode(&result); err != nil { - log.Printf("error reading broker response: %s", err.Error()) + log.Printf("error reading bridgestrap response: %s", err.Error()) log.Printf("body: %s", resp.Body) return } - log.Printf("offer:%s", result) + log.Printf("Throughput: %f Kbps", result.Throughput) + log.Printf("Latency: %d", result.Latency) } } diff --git a/proxy-go/throughput.go b/proxy-go/throughput.go index 9e5e274..011be3d 100644 --- a/proxy-go/throughput.go +++ b/proxy-go/throughput.go @@ -18,9 +18,9 @@ type SnowflakeAnswer struct { } type SnowflakeResult struct { - Throughput string `json:"throughput"` - Latency string `json:"latency"` - Error string `json:"error"` + Throughput float64 `json:"throughput"` + Latency int `json:"latency"` + Error string `json:"error"` } func CreateSnowflakeRequest(id string) []byte { From 9c5f44eb8b61ff5a7dad5c75afa4256de948c5c6 Mon Sep 17 00:00:00 2001 From: Cecylia Bocovich Date: Thu, 27 Feb 2020 11:48:09 -0500 Subject: [PATCH 7/8] Refactor to clean up and reuse code --- proxy-go/proxy-go_test.go | 4 +- proxy-go/snowflake.go | 190 +++++++++++++++++--------------------- proxy-go/throughput.go | 2 +- 3 files changed, 90 insertions(+), 106 deletions(-) diff --git a/proxy-go/proxy-go_test.go b/proxy-go/proxy-go_test.go index ebe4381..3b00078 100644 --- a/proxy-go/proxy-go_test.go +++ b/proxy-go/proxy-go_test.go @@ -227,7 +227,7 @@ func TestBrokerInteractions(t *testing.T) { const sampleAnswer = `{"type":"answer","sdp":` + sampleSDP + `}` Convey("Proxy connections to broker", t, func() { - broker := new(Broker) + broker := new(Remote) broker.url, _ = url.Parse("localhost") //Mock peerConnection @@ -307,7 +307,7 @@ func TestBrokerInteractions(t *testing.T) { } err = broker.sendAnswer("test", pc) So(err, ShouldNotEqual, nil) - So(err.Error(), ShouldResemble, "broker returned 410") + So(err.Error(), ShouldResemble, "error sending answer to broker: remote returned status code 410") //Error if we can't parse broker message broker.transport = &MockTransport{ diff --git a/proxy-go/snowflake.go b/proxy-go/snowflake.go index e4c34e9..5a3bd71 100644 --- a/proxy-go/snowflake.go +++ b/proxy-go/snowflake.go @@ -28,6 +28,7 @@ import ( const defaultBrokerURL = "https://snowflake-broker.bamsoftware.com/" const defaultRelayURL = "wss://snowflake.bamsoftware.com/" +const defaultProbeURL = "http://159.203.63.110:8080" const defaultSTUNURL = "stun:stun.l.google.com:19302" const pollInterval = 5 * time.Second @@ -37,7 +38,7 @@ const dataChannelTimeout = 20 * time.Second const readLimit = 100000 //Maximum number of bytes to be read from an HTTP request -var broker *Broker +var broker *Remote var relayURL string const ( @@ -69,11 +70,6 @@ func remoteIPFromSDP(sdp string) net.IP { return nil } -type Broker struct { - url *url.URL - transport http.RoundTripper -} - type webRTCConn struct { dc *webrtc.DataChannel pc *webrtc.PeerConnection @@ -158,8 +154,32 @@ func limitedRead(r io.Reader, limit int64) ([]byte, error) { return p, err } -func (b *Broker) pollOffer(sid string) *webrtc.SessionDescription { - brokerPath := b.url.ResolveReference(&url.URL{Path: "proxy"}) +type Remote struct { + url *url.URL + transport http.RoundTripper +} + +func (r *Remote) MakePost(path string, payload io.Reader) ([]byte, error) { + + req, err := http.NewRequest("POST", path, payload) + if err != nil { + return nil, err + } + resp, err := r.transport.RoundTrip(req) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("remote returned status code %d", resp.StatusCode) + } + + defer resp.Body.Close() + return limitedRead(resp.Body, readLimit) +} + +func (r *Remote) pollOffer(sid string) *webrtc.SessionDescription { + brokerPath := r.url.ResolveReference(&url.URL{Path: "proxy"}) timeOfNextPoll := time.Now() for { // Sleep until we're scheduled to poll again. @@ -178,56 +198,36 @@ func (b *Broker) pollOffer(sid string) *webrtc.SessionDescription { log.Printf("Error encoding poll message: %s", err.Error()) return nil } - req, _ := http.NewRequest("POST", brokerPath.String(), bytes.NewBuffer(body)) - resp, err := b.transport.RoundTrip(req) + response, err := r.MakePost(brokerPath.String(), bytes.NewBuffer(body)) if err != nil { - log.Printf("error polling broker: %s", err) - } else { - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - log.Printf("broker returns: %d", resp.StatusCode) - } else { - body, err := limitedRead(resp.Body, readLimit) - if err != nil { - log.Printf("error reading broker response: %s", err) - } else { - - offer, err := messages.DecodePollResponse(body) - if err != nil { - log.Printf("error reading broker response: %s", err.Error()) - log.Printf("body: %s", body) - return nil - } - if offer != "" { - return deserializeSessionDescription(offer) - } - } - } + log.Printf("error polling broker: %s", err.Error()) + return nil + } + offer, err := messages.DecodePollResponse(response) + if err != nil { + log.Printf("error reading broker response: %s", err.Error()) + log.Printf("body: %s", body) + return nil + } + if offer != "" { + return deserializeSessionDescription(offer) } } } -func (b *Broker) sendAnswer(sid string, pc *webrtc.PeerConnection) error { - brokerPath := b.url.ResolveReference(&url.URL{Path: "answer"}) +func (r *Remote) sendAnswer(sid string, pc *webrtc.PeerConnection) error { + brokerPath := r.url.ResolveReference(&url.URL{Path: "answer"}) answer := string([]byte(serializeSessionDescription(pc.LocalDescription()))) body, err := messages.EncodeAnswerRequest(answer, sid) if err != nil { return err } - req, _ := http.NewRequest("POST", brokerPath.String(), bytes.NewBuffer(body)) - resp, err := b.transport.RoundTrip(req) + response, err := r.MakePost(brokerPath.String(), bytes.NewBuffer(body)) if err != nil { - return err - } - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("broker returned %d", resp.StatusCode) + return fmt.Errorf("error sending answer to broker: %s", err.Error()) } - body, err = limitedRead(resp.Body, readLimit) - if err != nil { - return fmt.Errorf("error reading broker response: %s", err) - } - success, err := messages.DecodeAnswerResponse(body) + success, err := messages.DecodeAnswerResponse(response) if err != nil { return err } @@ -290,6 +290,16 @@ func datachannelHandler(conn *webRTCConn) { log.Printf("datachannelHandler ends") } +// Handler for the throughput test +func throughputHandler(conn *webRTCConn) { + defer conn.Close() + + if _, err := io.Copy(conn, conn); err != nil { + log.Printf("io.Copy inside CopyLoop generated an error: %v", err) + } + +} + // Create a PeerConnection from an SDP offer. Blocks until the gathering of ICE // candidates is complete and the answer is available in LocalDescription. // Installs an OnDataChannel callback that creates a webRTCConn and passes it to @@ -406,52 +416,30 @@ func runSession(sid string) { } } -func throughputHandler(conn *webRTCConn) { - defer conn.Close() - - if _, err := io.Copy(conn, conn); err != nil { - log.Printf("io.Copy inside CopyLoop generated an error: %v", err) - } - -} - -func testThroughput(config webrtc.Configuration) { +func testThroughput(config webrtc.Configuration, probeURL string) { var err error var offer SnowflakeOffer var result SnowflakeResult - probe := new(Broker) + sessionID := genSessionID() + + probe := new(Remote) probe.transport = http.DefaultTransport.(*http.Transport) - probe.url, err = url.Parse("159.203.63.110") //hard code this for now + probe.url, err = url.Parse(probeURL) if err != nil { - log.Fatalf("invalid probe url: %s", err) + log.Printf("Error parsing url: %s", err.Error()) } - brokerPath := probe.url.ResolveReference(&url.URL{Scheme: "http", Host: "159.203.63.110:8080", Path: "api/snowflake-poll"}) - - sessionID := genSessionID() + probePath := probe.url.ResolveReference(&url.URL{Path: "api/snowflake-poll"}) - req, err := http.NewRequest("POST", brokerPath.String(), bytes.NewBuffer(CreateSnowflakeRequest(sessionID))) + response, err := probe.MakePost(probePath.String(), bytes.NewBuffer(CreateSnowflakeRequest(sessionID))) if err != nil { - log.Printf("Error creating request: %s", err.Error()) + log.Printf("Error connecting to probe point: %s", err.Error()) return } - resp, err := probe.transport.RoundTrip(req) - if err != nil { - log.Printf("error polling broker: %s", err) - } else { - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - log.Printf("proxy returns: %d", resp.StatusCode) - } else { - decoder := json.NewDecoder(resp.Body) - if err = decoder.Decode(&offer); err != nil { - log.Printf("error reading bridgestrap response: %s", err.Error()) - log.Printf("body: %s", resp.Body) - return - } - - log.Printf("offer:%s", offer) - } + if err = json.Unmarshal(response, &offer); err != nil { + log.Printf("error reading bridgestrap response: %s", err.Error()) + log.Printf("body: %s", response) + return } sdp := deserializeSessionDescription(offer.Offer) @@ -469,32 +457,22 @@ func testThroughput(config webrtc.Configuration) { // send answer testReq := CreateSnowflakeAnswer(sessionID, serializeSessionDescription(answer)) - brokerPath = probe.url.ResolveReference(&url.URL{Scheme: "http", Host: "159.203.63.110:8080", Path: "api/snowflake-test"}) - req, err = http.NewRequest("POST", brokerPath.String(), bytes.NewBuffer(testReq)) + probePath = probe.url.ResolveReference(&url.URL{Path: "api/snowflake-test"}) + + response, err = probe.MakePost(probePath.String(), bytes.NewBuffer(testReq)) if err != nil { - log.Printf("Error creating request: %s", err.Error()) + log.Printf("Error connecting to probe point: %s", err.Error()) return } - resp, err = probe.transport.RoundTrip(req) - if err != nil { - log.Printf("error polling broker: %s", err) - } else { - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - log.Printf("proxy returns: %d", resp.StatusCode) - } else { - decoder := json.NewDecoder(resp.Body) - if err = decoder.Decode(&result); err != nil { - log.Printf("error reading bridgestrap response: %s", err.Error()) - log.Printf("body: %s", resp.Body) - return - } - - log.Printf("Throughput: %f Kbps", result.Throughput) - log.Printf("Latency: %d", result.Latency) - } + if err = json.Unmarshal(response, &result); err != nil { + log.Printf("error reading bridgestrap response: %s", err.Error()) + log.Printf("body: %s", response) + return } + log.Printf("Throughput: %f Kbps", result.Throughput) + log.Printf("Latency: %f s", result.Latency) + } func main() { @@ -502,10 +480,12 @@ func main() { var stunURL string var logFilename string var rawBrokerURL string + var probeURL string flag.UintVar(&capacity, "capacity", 10, "maximum concurrent clients") flag.StringVar(&rawBrokerURL, "broker", defaultBrokerURL, "broker URL") flag.StringVar(&relayURL, "relay", defaultRelayURL, "websocket relay URL") + flag.StringVar(&probeURL, "probe", defaultProbeURL, "URL for throughput testing probe") flag.StringVar(&stunURL, "stun", defaultSTUNURL, "stun URL") flag.StringVar(&logFilename, "log", "", "log filename") flag.Parse() @@ -526,7 +506,7 @@ func main() { log.Println("starting") var err error - broker = new(Broker) + broker = new(Remote) broker.url, err = url.Parse(rawBrokerURL) if err != nil { log.Fatalf("invalid broker url: %s", err) @@ -539,6 +519,10 @@ func main() { if err != nil { log.Fatalf("invalid relay url: %s", err) } + _, err = url.Parse(probeURL) + if err != nil { + log.Fatalf("invalid probe url: %s", err) + } broker.transport = http.DefaultTransport.(*http.Transport) config = webrtc.Configuration{ @@ -554,7 +538,7 @@ func main() { } //Perform a throughput test - testThroughput(config) + testThroughput(config, probeURL) for { getToken() diff --git a/proxy-go/throughput.go b/proxy-go/throughput.go index 011be3d..97dd5c3 100644 --- a/proxy-go/throughput.go +++ b/proxy-go/throughput.go @@ -19,7 +19,7 @@ type SnowflakeAnswer struct { type SnowflakeResult struct { Throughput float64 `json:"throughput"` - Latency int `json:"latency"` + Latency float64 `json:"latency"` Error string `json:"error"` } From 3d3ece2eb17970fce8464826e93da0ce1003dc10 Mon Sep 17 00:00:00 2001 From: Cecylia Bocovich Date: Thu, 27 Feb 2020 12:15:29 -0500 Subject: [PATCH 8/8] Repeat throughput test every 24 hours --- proxy-go/snowflake.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/proxy-go/snowflake.go b/proxy-go/snowflake.go index 5a3bd71..9e27250 100644 --- a/proxy-go/snowflake.go +++ b/proxy-go/snowflake.go @@ -539,6 +539,12 @@ func main() { //Perform a throughput test testThroughput(config, probeURL) + go func() { + heartbeat := time.Tick(24 * time.Hour) + for range heartbeat { + testThroughput(config, probeURL) + } + }() for { getToken()