From f4db64612c500be635dc7eb231505e88552e6a07 Mon Sep 17 00:00:00 2001 From: WofWca Date: Thu, 22 Aug 2024 11:18:42 +0400 Subject: [PATCH] feat: expose `pollInterval` in CLI Closes https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/issues/40373 --- proxy/README.md | 2 ++ proxy/lib/proxy-go_test.go | 4 ++-- proxy/lib/snowflake.go | 24 ++++++++++++++---------- proxy/main.go | 9 +++++++++ 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/proxy/README.md b/proxy/README.md index bda8f93..76cdcfb 100644 --- a/proxy/README.md +++ b/proxy/README.md @@ -35,6 +35,8 @@ Usage of ./proxy: a pattern to specify allowed hostname pattern for relay URL. (default "snowflake.torproject.net$") -broker string broker URL (default "https://snowflake-broker.torproject.net/") + -poll-interval duration + how often to ask the broker for a new client. Keep in mind that asking for a client will not always result in getting one. Minumum value is 2s. Valid time units are "ms", "s", "m", "h". (default 5s) -capacity uint maximum concurrent clients (default is to accept an unlimited number of clients) -disableStatsLogger diff --git a/proxy/lib/proxy-go_test.go b/proxy/lib/proxy-go_test.go index 50be0da..7c46480 100644 --- a/proxy/lib/proxy-go_test.go +++ b/proxy/lib/proxy-go_test.go @@ -364,7 +364,7 @@ func TestBrokerInteractions(t *testing.T) { b, } - sdp, _ := broker.pollOffer(sampleOffer, DefaultProxyType, "", nil) + sdp, _ := broker.pollOffer(sampleOffer, DefaultProxyType, "", DefaultPollInterval, nil) expectedSDP, _ := strconv.Unquote(sampleSDP) So(sdp.SDP, ShouldResemble, expectedSDP) }) @@ -378,7 +378,7 @@ func TestBrokerInteractions(t *testing.T) { b, } - sdp, _ := broker.pollOffer(sampleOffer, DefaultProxyType, "", nil) + sdp, _ := broker.pollOffer(sampleOffer, DefaultProxyType, "", DefaultPollInterval, nil) So(sdp, ShouldBeNil) }) Convey("sends answer to broker", func() { diff --git a/proxy/lib/snowflake.go b/proxy/lib/snowflake.go index 3c333a1..65b4703 100644 --- a/proxy/lib/snowflake.go +++ b/proxy/lib/snowflake.go @@ -53,11 +53,12 @@ import ( ) const ( - DefaultBrokerURL = "https://snowflake-broker.torproject.net/" - DefaultNATProbeURL = "https://snowflake-broker.torproject.net:8443/probe" - DefaultRelayURL = "wss://snowflake.torproject.net/" - DefaultSTUNURL = "stun:stun.l.google.com:19302" - DefaultProxyType = "standalone" + DefaultPollInterval = 5 * time.Second + DefaultBrokerURL = "https://snowflake-broker.torproject.net/" + DefaultNATProbeURL = "https://snowflake-broker.torproject.net:8443/probe" + DefaultRelayURL = "wss://snowflake.torproject.net/" + DefaultSTUNURL = "stun:stun.l.google.com:19302" + DefaultProxyType = "standalone" ) const ( @@ -72,8 +73,6 @@ const ( ) const ( - pollInterval = 5 * time.Second - // Amount of time after sending an SDP answer before the proxy assumes the // client is not going to connect dataChannelTimeout = 20 * time.Second @@ -115,6 +114,8 @@ var ( // SnowflakeProxy is used to configure an embedded // Snowflake in another Go application. type SnowflakeProxy struct { + // How often to ask the broker for a new client + PollInterval time.Duration // Capacity is the maximum number of clients a Snowflake will serve. // Proxies with a capacity of 0 will accept an unlimited number of clients. Capacity uint @@ -221,7 +222,7 @@ func (s *SignalingServer) Post(path string, payload io.Reader) ([]byte, error) { // pollOffer communicates the proxy's capabilities with broker // and retrieves a compatible SDP offer -func (s *SignalingServer) pollOffer(sid string, proxyType string, acceptedRelayPattern string, shutdown chan struct{}) (*webrtc.SessionDescription, string) { +func (s *SignalingServer) pollOffer(sid string, proxyType string, acceptedRelayPattern string, pollInterval time.Duration, shutdown chan struct{}) (*webrtc.SessionDescription, string) { brokerPath := s.url.ResolveReference(&url.URL{Path: "proxy"}) ticker := time.NewTicker(pollInterval) @@ -591,7 +592,7 @@ func (sf *SnowflakeProxy) makeNewPeerConnection( } func (sf *SnowflakeProxy) runSession(sid string) { - offer, relayURL := broker.pollOffer(sid, sf.ProxyType, sf.RelayDomainNamePattern, sf.shutdown) + offer, relayURL := broker.pollOffer(sid, sf.ProxyType, sf.RelayDomainNamePattern, sf.PollInterval, sf.shutdown) if offer == nil { log.Printf("bad offer from broker") tokens.ret() @@ -655,6 +656,9 @@ func (sf *SnowflakeProxy) Start() error { sf.shutdown = make(chan struct{}) // blank configurations revert to default + if sf.PollInterval == 0 { + sf.PollInterval = DefaultPollInterval + } if sf.BrokerURL == "" { sf.BrokerURL = DefaultBrokerURL } @@ -729,7 +733,7 @@ func (sf *SnowflakeProxy) Start() error { defer NatRetestTask.Close() } - ticker := time.NewTicker(pollInterval) + ticker := time.NewTicker(sf.PollInterval) defer ticker.Stop() for ; true; <-ticker.C { diff --git a/proxy/main.go b/proxy/main.go index cec6e3e..675cf3b 100644 --- a/proxy/main.go +++ b/proxy/main.go @@ -17,7 +17,11 @@ import ( sf "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/proxy/lib" ) +const minPollInterval = 2 * time.Second + func main() { + pollInterval := flag.Duration("poll-interval", sf.DefaultPollInterval, + fmt.Sprint("how often to ask the broker for a new client. Keep in mind that asking for a client will not always result in getting one. Minumum value is ", minPollInterval, ". Valid time units are \"ms\", \"s\", \"m\", \"h\".")) capacity := flag.Uint("capacity", 0, "maximum concurrent clients (default is to accept an unlimited number of clients)") stunURL := flag.String("stun", sf.DefaultSTUNURL, "STUN URL") logFilename := flag.String("log", "", "log filename") @@ -50,6 +54,10 @@ func main() { os.Exit(0) } + if *pollInterval < minPollInterval { + log.Fatalf("poll-interval must be >= %v", minPollInterval) + } + if *outboundAddress != "" && *keepLocalAddresses { log.Fatal("Cannot keep local address candidates when outbound address is specified") } @@ -83,6 +91,7 @@ func main() { } proxy := sf.SnowflakeProxy{ + PollInterval: *pollInterval, Capacity: uint(*capacity), STUNURL: *stunURL, BrokerURL: *rawBrokerURL,