diff options
| -rw-r--r-- | constants/constants.go | 9 | ||||
| -rw-r--r-- | lgc/lgc.go | 72 | ||||
| -rw-r--r-- | networkQuality.go | 81 | ||||
| -rw-r--r-- | timeoutat/timeoutat.go | 9 | ||||
| -rw-r--r-- | utilities/utilities.go | 23 |
5 files changed, 122 insertions, 72 deletions
diff --git a/constants/constants.go b/constants/constants.go index 1a060dd..02038a3 100644 --- a/constants/constants.go +++ b/constants/constants.go @@ -31,3 +31,12 @@ var ( // The default URL for the config host. DefaultConfigHost string = "networkquality.example.com" ) + +type DebugLevel int8 + +const ( + NoDebug DebugLevel = iota + Debug + Warn + Error +) @@ -25,6 +25,7 @@ import ( "sync/atomic" "time" + "github.com/network-quality/goresponsiveness/constants" "github.com/network-quality/goresponsiveness/utilities" "golang.org/x/net/http2" ) @@ -37,7 +38,7 @@ var GenerateConnectionId func() uint64 = func() func() uint64 { }() type LoadGeneratingConnection interface { - Start(context.Context, bool) bool + Start(context.Context, constants.DebugLevel) bool Transferred() uint64 Client() *http.Client IsValid() bool @@ -64,7 +65,7 @@ type LoadGeneratingConnectionDownload struct { Path string downloaded uint64 client *http.Client - debug bool + debug constants.DebugLevel valid bool KeyLogger io.Writer clientId uint64 @@ -79,7 +80,7 @@ func generateHttpTimingTracer( DNSStart: func(dnsStartInfo httptrace.DNSStartInfo) { lgd.stats.dnsStartTime = time.Now() lgd.stats.dnsStart = dnsStartInfo - if lgd.debug { + if utilities.IsDebug(lgd.debug) { fmt.Printf( "DNS Start for %v: %v\n", lgd.ClientId(), @@ -90,13 +91,13 @@ func generateHttpTimingTracer( DNSDone: func(dnsDoneInfo httptrace.DNSDoneInfo) { lgd.stats.dnsCompleteTime = time.Now() lgd.stats.dnsDone = dnsDoneInfo - if lgd.debug { + if utilities.IsDebug(lgd.debug) { fmt.Printf("DNS Done for %v: %v\n", lgd.ClientId(), dnsDoneInfo) } }, ConnectStart: func(network, address string) { lgd.stats.connectStartTime = time.Now() - if lgd.debug { + if utilities.IsDebug(lgd.debug) { fmt.Printf( "TCP Start of %v: %v: %v\n", lgd.ClientId(), @@ -107,7 +108,7 @@ func generateHttpTimingTracer( }, ConnectDone: func(network, address string, err error) { lgd.stats.connectCompleteTime = time.Now() - if lgd.debug { + if utilities.IsDebug(lgd.debug) { fmt.Printf( "TCP Done for %v: %v: %v (%v)\n", lgd.ClientId(), @@ -119,7 +120,7 @@ func generateHttpTimingTracer( }, GetConn: func(hostPort string) { lgd.stats.getConnectionStartTime = time.Now() - if lgd.debug { + if utilities.IsDebug(lgd.debug) { fmt.Printf( "GetConn host port for %v: %v\n", lgd.ClientId(), @@ -133,7 +134,7 @@ func generateHttpTimingTracer( } lgd.stats.connInfo = connInfo lgd.stats.getConnectionCompleteTime = time.Now() - if lgd.debug { + if utilities.IsDebug(lgd.debug) { fmt.Printf( "GetConn host port for %v: %v\n", lgd.ClientId(), @@ -143,14 +144,14 @@ func generateHttpTimingTracer( }, TLSHandshakeStart: func() { lgd.stats.tlsStartTime = time.Now() - if lgd.debug { + if utilities.IsDebug(lgd.debug) { fmt.Printf("TLSHandshakeStart for %v\n", lgd.ClientId()) } }, TLSHandshakeDone: func(tlsConnState tls.ConnectionState, err error) { lgd.stats.tlsCompleteTime = time.Now() lgd.stats.tlsConnInfo = tlsConnState - if lgd.debug { + if utilities.IsDebug(lgd.debug) { fmt.Printf( "TLSHandshakeDone for %v: %v\n", lgd.ClientId(), @@ -168,7 +169,7 @@ func (lbd *LoadGeneratingConnectionDownload) ClientId() uint64 { func (lbd *LoadGeneratingConnectionDownload) Transferred() uint64 { transferred := atomic.LoadUint64(&lbd.downloaded) - if lbd.debug { + if utilities.IsDebug(lbd.debug) { fmt.Printf("download: Transferred: %v\n", transferred) } return transferred @@ -195,14 +196,15 @@ func (cr *countingReader) Read(p []byte) (n int, err error) { func (lbd *LoadGeneratingConnectionDownload) Start( ctx context.Context, - debug bool, + debug constants.DebugLevel, ) bool { lbd.downloaded = 0 lbd.clientId = GenerateConnectionId() transport := http2.Transport{} + transport.TLSClientConfig = &tls.Config{} if !utilities.IsInterfaceNil(lbd.KeyLogger) { - if debug { + if utilities.IsDebug(lbd.debug) { fmt.Printf( "Using an SSL Key Logger for this load-generating download.\n", ) @@ -215,18 +217,16 @@ func (lbd *LoadGeneratingConnectionDownload) Start( // depend on whether the url contains // https:// or http://: // https://github.com/golang/go/blob/7ca6902c171b336d98adbb103d701a013229c806/src/net/http/transport.go#L74 - transport.TLSClientConfig = &tls.Config{ - KeyLogWriter: lbd.KeyLogger, - InsecureSkipVerify: true, - } + transport.TLSClientConfig.KeyLogWriter = lbd.KeyLogger } + transport.TLSClientConfig.InsecureSkipVerify = true lbd.client = &http.Client{Transport: &transport} lbd.debug = debug lbd.valid = true lbd.tracer = generateHttpTimingTracer(lbd) - if debug { + if utilities.IsDebug(debug) { fmt.Printf( "Started a load-generating download (id: %v).\n", lbd.clientId, @@ -240,22 +240,28 @@ func (lbd *LoadGeneratingConnectionDownload) IsValid() bool { } func (lbd *LoadGeneratingConnectionDownload) doDownload(ctx context.Context) { - newRequest, err := http.NewRequestWithContext( + var request *http.Request = nil + var get *http.Response = nil + var err error = nil + + if request, err = http.NewRequestWithContext( httptrace.WithClientTrace(ctx, lbd.tracer), "GET", lbd.Path, nil, - ) + ); err != nil { + lbd.valid = false + return + } - get, err := lbd.client.Do(newRequest) - if err != nil { + if get, err = lbd.client.Do(request); err != nil { lbd.valid = false return } cr := &countingReader{n: &lbd.downloaded, ctx: ctx, readable: get.Body} _, _ = io.Copy(ioutil.Discard, cr) get.Body.Close() - if lbd.debug { + if utilities.IsDebug(lbd.debug) { fmt.Printf("Ending a load-generating download.\n") } } @@ -264,7 +270,7 @@ type LoadGeneratingConnectionUpload struct { Path string uploaded uint64 client *http.Client - debug bool + debug constants.DebugLevel valid bool KeyLogger io.Writer clientId uint64 @@ -276,7 +282,7 @@ func (lbu *LoadGeneratingConnectionUpload) ClientId() uint64 { func (lbu *LoadGeneratingConnectionUpload) Transferred() uint64 { transferred := atomic.LoadUint64(&lbu.uploaded) - if lbu.debug { + if utilities.IsDebug(lbu.debug) { fmt.Printf("upload: Transferred: %v\n", transferred) } return transferred @@ -314,9 +320,10 @@ func (lbu *LoadGeneratingConnectionUpload) doUpload(ctx context.Context) bool { if resp, err = lbu.client.Post(lbu.Path, "application/octet-stream", s); err != nil { lbu.valid = false + return false } resp.Body.Close() - if lbu.debug { + if utilities.IsDebug(lbu.debug) { fmt.Printf("Ending a load-generating upload.\n") } return true @@ -324,7 +331,7 @@ func (lbu *LoadGeneratingConnectionUpload) doUpload(ctx context.Context) bool { func (lbu *LoadGeneratingConnectionUpload) Start( ctx context.Context, - debug bool, + debug constants.DebugLevel, ) bool { lbu.uploaded = 0 lbu.clientId = GenerateConnectionId() @@ -332,24 +339,23 @@ func (lbu *LoadGeneratingConnectionUpload) Start( // See above for the rationale of doing http2.Transport{} here // to ensure that we are using h2. transport := http2.Transport{} + transport.TLSClientConfig = &tls.Config{} if !utilities.IsInterfaceNil(lbu.KeyLogger) { - if debug { + if utilities.IsDebug(lbu.debug) { fmt.Printf( "Using an SSL Key Logger for this load-generating upload.\n", ) } - transport.TLSClientConfig = &tls.Config{ - KeyLogWriter: lbu.KeyLogger, - InsecureSkipVerify: true, - } + transport.TLSClientConfig.KeyLogWriter = lbu.KeyLogger } + transport.TLSClientConfig.InsecureSkipVerify = true lbu.client = &http.Client{Transport: &transport} lbu.debug = debug lbu.valid = true - if debug { + if utilities.IsDebug(lbu.debug) { fmt.Printf("Started a load-generating upload (id: %v).\n", lbu.clientId) } go lbu.doUpload(ctx) diff --git a/networkQuality.go b/networkQuality.go index d450bf4..a7c7756 100644 --- a/networkQuality.go +++ b/networkQuality.go @@ -57,7 +57,11 @@ var ( "config", "path on the server to the configuration endpoint.", ) - debug = flag.Bool("debug", constants.DefaultDebug, "Enable debugging.") + debugCliFlag = flag.Bool( + "debug", + constants.DefaultDebug, + "Enable debugging.", + ) timeout = flag.Int( "timeout", constants.DefaultTestTime, @@ -201,7 +205,7 @@ func addFlows( lgcs *[]lgc.LoadGeneratingConnection, lgcsPreviousTransferred *[]uint64, lgcGenerator func() lgc.LoadGeneratingConnection, - debug bool, + debug constants.DebugLevel, ) { for i := uint64(0); i < toAdd; i++ { *lgcs = append(*lgcs, lgcGenerator()) @@ -222,11 +226,12 @@ type SaturationResult struct { } type Debugging struct { + Level constants.DebugLevel Prefix string } -func NewDebugging(prefix string) *Debugging { - return &Debugging{Prefix: prefix} +func NewDebugging(level constants.DebugLevel, prefix string) *Debugging { + return &Debugging{Level: level, Prefix: prefix} } func (d *Debugging) String() string { @@ -251,7 +256,7 @@ func saturate( &lgcs, &lgcsPreviousTransferred, lgcGenerator, - debug != nil, + debug.Level, ) previousFlowIncreaseIteration := uint64(0) @@ -281,7 +286,7 @@ func saturate( now := time.Now() // At each 1-second interval if nextSampleStartTime.Sub(now) > 0 { - if debug != nil { + if utilities.IsDebug(debug.Level) { fmt.Printf( "%v: Sleeping until %v\n", debug, @@ -300,7 +305,7 @@ func saturate( allInvalid := true for i := range lgcs { if !lgcs[i].IsValid() { - if debug != nil { + if utilities.IsDebug(debug.Level) { fmt.Printf( "%v: Load-generating connection with id %d is invalid ... skipping.\n", debug, @@ -319,7 +324,7 @@ func saturate( // For some reason, all the lgcs are invalid. This likely means that // the network/server went away. if allInvalid { - if debug != nil { + if utilities.IsDebug(debug.Level) { fmt.Printf( "%v: All lgcs were invalid. Assuming that network/server went away.\n", debug, @@ -339,7 +344,7 @@ func saturate( previousMovingAverage, ) - if debug != nil { + if utilities.IsDebug(debug.Level) { fmt.Printf( "%v: Instantaneous goodput: %f MB.\n", debug, @@ -377,7 +382,7 @@ func saturate( if (currentIteration - previousFlowIncreaseIteration) > uint64( constants.MovingAverageStabilitySpan, ) { - if debug != nil { + if utilities.IsDebug(debug.Level) { fmt.Printf( "%v: Adding flows because we are unsaturated and waited a while.\n", debug, @@ -389,31 +394,31 @@ func saturate( &lgcs, &lgcsPreviousTransferred, lgcGenerator, - debug != nil, + debug.Level, ) previousFlowIncreaseIteration = currentIteration } else { - if debug != nil { + if utilities.IsDebug(debug.Level) { fmt.Printf("%v: We are unsaturated, but it still too early to add anything.\n", debug) } } } else { // Else, network reached saturation for the current flow count. - if debug != nil { + if utilities.IsDebug(debug.Level) { fmt.Printf("%v: Network reached saturation with current flow count.\n", debug) } // If new flows added and for 4 seconds the moving average // throughput did not change: network reached stable saturation if (currentIteration-previousFlowIncreaseIteration) < uint64(constants.MovingAverageStabilitySpan) && movingAverageAverage.AllSequentialIncreasesLessThan(float64(5)) { - if debug != nil { + if utilities.IsDebug(debug.Level) { fmt.Printf("%v: New flows added within the last four seconds and the moving-average average is consistent!\n", debug) } break } else { // Else, add four more flows - if debug != nil { + if utilities.IsDebug(debug.Level) { fmt.Printf("%v: New flows to add to try to increase our saturation!\n", debug) } - addFlows(saturationCtx, constants.AdditiveNumberOfLoadGeneratingConnections, &lgcs, &lgcsPreviousTransferred, lgcGenerator, debug != nil) + addFlows(saturationCtx, constants.AdditiveNumberOfLoadGeneratingConnections, &lgcs, &lgcsPreviousTransferred, lgcGenerator, debug.Level) previousFlowIncreaseIteration = currentIteration } } @@ -435,6 +440,11 @@ func main() { context.Background(), ) config := &Config{} + var debugLevel constants.DebugLevel = constants.Error + + if *debugCliFlag { + debugLevel = constants.Debug + } if err := config.Get(configHostPort, *configPath); err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) @@ -449,16 +459,16 @@ func main() { ) return } - if *debug { + if utilities.IsDebug(debugLevel) { fmt.Printf("Configuration: %s\n", config) } timeoutChannel := timeoutat.TimeoutAt( operatingCtx, timeoutAbsoluteTime, - *debug, + debugLevel, ) - if *debug { + if utilities.IsDebug(debugLevel) { fmt.Printf("Test will end earlier than %v\n", timeoutAbsoluteTime) } @@ -495,7 +505,7 @@ func main() { fmt.Printf("Could not seek to the end of the key file: %v!\n", err) sslKeyFileConcurrentWriter = nil } else { - if *debug { + if utilities.IsDebug(debugLevel) { fmt.Printf("Doing SSL key logging through file %v\n", *sslKeyFileName) } sslKeyFileConcurrentWriter = ccw.NewConcurrentFileWriter(sslKeyFileHandle) @@ -519,7 +529,7 @@ func main() { var downloadDebugging *Debugging = nil var uploadDebugging *Debugging = nil - if *debug { + if utilities.IsDebug(debugLevel) { downloadDebugging = &Debugging{Prefix: "download"} uploadDebugging = &Debugging{Prefix: "upload"} } @@ -548,7 +558,7 @@ func main() { case downloadSaturation = <-downloadSaturationChannel: { downloadSaturated = true - if *debug { + if *debugCliFlag { fmt.Printf( "################# download is %s saturated (%fMBps, %d flows)!\n", utilities.Conditional( @@ -564,7 +574,7 @@ func main() { case uploadSaturation = <-uploadSaturationChannel: { uploadSaturated = true - if *debug { + if *debugCliFlag { fmt.Printf( "################# upload is %s saturated (%fMBps, %d flows)!\n", utilities.Conditional( @@ -588,7 +598,7 @@ func main() { "Error: Saturation could not be completed in time and no provisional rates could be accessed. Test failed.\n", ) cancelOperatingCtx() - if *debug { + if *debugCliFlag { time.Sleep(constants.CooldownPeriod) } return @@ -605,9 +615,9 @@ func main() { timeoutChannel = timeoutat.TimeoutAt( operatingCtx, timeoutAbsoluteTime, - *debug, + debugLevel, ) - if *debug { + if *debugCliFlag { fmt.Printf( "################# timeout reaching saturation!\n", ) @@ -625,7 +635,7 @@ func main() { timeoutChannel = timeoutat.TimeoutAt( operatingCtx, timeoutAbsoluteTime, - *debug, + debugLevel, ) } @@ -643,10 +653,10 @@ func main() { downloadSaturation.lgcs, ) if !downloadSaturation.lgcs[randomlgcsIndex].IsValid() { - if *debug { + if *debugCliFlag { fmt.Printf( "%v: The randomly selected download lgc (with id %d) was invalid. Skipping.\n", - debug, + debugCliFlag, downloadSaturation.lgcs[randomlgcsIndex].ClientId(), ) } @@ -655,7 +665,7 @@ func main() { // invalid connections and never // do the select below if time.Since(timeoutAbsoluteTime) > 0 { - if *debug { + if *debugCliFlag { fmt.Printf( "Pathologically could not find valid lgcs to use for measurement.\n", ) @@ -666,12 +676,11 @@ func main() { } newTransport := http2.Transport{} + newTransport.TLSClientConfig = &tls.Config{} if sslKeyFileConcurrentWriter != nil { - newTransport.TLSClientConfig = &tls.Config{ - KeyLogWriter: sslKeyFileConcurrentWriter, - InsecureSkipVerify: true, - } + newTransport.TLSClientConfig.KeyLogWriter = sslKeyFileConcurrentWriter } + newTransport.TLSClientConfig.InsecureSkipVerify = true newClient := http.Client{Transport: &newTransport} select { @@ -691,7 +700,7 @@ func main() { // We know that we have a good Sequential RTT. totalRTsCount += uint64(sequentialRTTimes.RoundTripCount) totalRTTimes += sequentialRTTimes.Delay.Seconds() - if *debug { + if *debugCliFlag { fmt.Printf( "sequentialRTTsTime: %v\n", sequentialRTTimes.Delay.Seconds(), @@ -740,7 +749,7 @@ func main() { } cancelOperatingCtx() - if *debug { + if *debugCliFlag { fmt.Printf("In debugging mode, we will cool down.\n") time.Sleep(constants.CooldownPeriod) fmt.Printf("Done cooling down.\n") diff --git a/timeoutat/timeoutat.go b/timeoutat/timeoutat.go index 0e13a9f..eac57f2 100644 --- a/timeoutat/timeoutat.go +++ b/timeoutat/timeoutat.go @@ -18,17 +18,20 @@ import ( "context" "fmt" "time" + + "github.com/network-quality/goresponsiveness/constants" + "github.com/network-quality/goresponsiveness/utilities" ) func TimeoutAt( ctx context.Context, when time.Time, - debug bool, + debug constants.DebugLevel, ) (response chan interface{}) { response = make(chan interface{}) go func(ctx context.Context) { go func() { - if debug { + if utilities.IsDebug(debug) { fmt.Printf("Timeout expected to end at %v\n", when) } select { @@ -36,7 +39,7 @@ func TimeoutAt( case <-ctx.Done(): } response <- struct{}{} - if debug { + if utilities.IsDebug(debug) { fmt.Printf("Timeout ended at %v\n", time.Now()) } }() diff --git a/utilities/utilities.go b/utilities/utilities.go index 46d5766..b8e416c 100644 --- a/utilities/utilities.go +++ b/utilities/utilities.go @@ -22,6 +22,8 @@ import ( "os" "reflect" "time" + + "github.com/network-quality/goresponsiveness/constants" ) func IsInterfaceNil(ifc interface{}) bool { @@ -121,3 +123,24 @@ func SeekForAppend(file *os.File) (err error) { _, err = file.Seek(0, 2) return } + +func IsDebug(level constants.DebugLevel) bool { + if level <= constants.Debug { + return true + } + return false +} + +func IsWarn(level constants.DebugLevel) bool { + if level <= constants.Warn { + return true + } + return false +} + +func IsError(level constants.DebugLevel) bool { + if level <= constants.Error { + return true + } + return false +} |
