diff options
| author | Will Hawkins <[email protected]> | 2022-08-17 22:07:35 -0400 |
|---|---|---|
| committer | Will Hawkins <[email protected]> | 2022-08-17 22:07:35 -0400 |
| commit | 18bcc4fe73bd8245cde001c939b400693a0d9410 (patch) | |
| tree | 1d38cdb6271153d0bc1ba4ddfc3218722b12ccf7 | |
| parent | 8d7b3f43988f40976c540e64f955fabe3d14d755 (diff) | |
[Feature] Add TCP information (RTT and Cwnd) to Logging
This patch adds support for logging the underlying RTT and Cwnd of the
TCP connection used when doing probes. More work to follow in order to
add support for this information on Windows and Darwin.
| -rw-r--r-- | datalogger/logger.go | 11 | ||||
| -rw-r--r-- | extendedstats/other.go | 6 | ||||
| -rw-r--r-- | extendedstats/unix.go | 29 | ||||
| -rw-r--r-- | go.mod | 2 | ||||
| -rw-r--r-- | go.sum | 6 | ||||
| -rw-r--r-- | networkQuality.go | 2 | ||||
| -rw-r--r-- | rpm/rpm.go | 18 |
7 files changed, 42 insertions, 32 deletions
diff --git a/datalogger/logger.go b/datalogger/logger.go index 1a4cd20..6236b59 100644 --- a/datalogger/logger.go +++ b/datalogger/logger.go @@ -66,19 +66,20 @@ func doCustomFormatting(value reflect.Value, tag reflect.StructTag) (string, err } formatMethodArgument, success := tag.Lookup("FormatterArgument") if !success { - return "", fmt.Errorf("Could not find the formatter name") + formatMethodArgument = "" } formatMethod := value.MethodByName(formatMethodName) if formatMethod == reflect.ValueOf(0) { return "", fmt.Errorf("Type %v does not support a method named %v", value.Type(), formatMethodName) } - - formatMethodArgumentUsable := make([]reflect.Value, 1) - formatMethodArgumentUsable[0] = reflect.ValueOf(formatMethodArgument) + var formatMethodArgumentUsable []reflect.Value = make([]reflect.Value, 0) + if formatMethodArgument != "" { + formatMethodArgumentUsable = append(formatMethodArgumentUsable, reflect.ValueOf(formatMethodArgument)) + } result := formatMethod.Call(formatMethodArgumentUsable) if len(result) == 1 { - return result[0].String(), nil + return fmt.Sprintf("%v", result[0]), nil } return "", fmt.Errorf("Too many results returned by the format method's invocation.") } diff --git a/extendedstats/other.go b/extendedstats/other.go index b4eae18..50caef6 100644 --- a/extendedstats/other.go +++ b/extendedstats/other.go @@ -11,7 +11,7 @@ import ( type ExtendedStats struct{} func (es *ExtendedStats) IncorporateConnectionStats(conn net.Conn) error { - return fmt.Errorf("OOPS: IncorporateConnectionStats is not supported on this platform") + return fmt.Errorf("IncorporateConnectionStats is not supported on this platform") } func (es *ExtendedStats) Repr() string { @@ -21,3 +21,7 @@ func (es *ExtendedStats) Repr() string { func ExtendedStatsAvailable() bool { return false } + +func GetTCPInfo(basicConn net.Conn) (interface, error) { + return nil, fmt.Errorf("GetTCPInfo is not supported on this platform") +} diff --git a/extendedstats/unix.go b/extendedstats/unix.go index a2d4d30..3db94fc 100644 --- a/extendedstats/unix.go +++ b/extendedstats/unix.go @@ -27,20 +27,8 @@ func ExtendedStatsAvailable() bool { return true } -func (es *ExtendedStats) IncorporateConnectionStats(rawConn net.Conn) error { - tlsConn, ok := rawConn.(*tls.Conn) - if !ok { - return fmt.Errorf( - "OOPS: Could not get the TCP info for the connection (not a TLS connection)", - ) - } - tcpConn, ok := tlsConn.NetConn().(*net.TCPConn) - if !ok { - return fmt.Errorf( - "OOPS: Could not get the TCP info for the connection (not a TCP connection)", - ) - } - if info, err := getTCPInfo(tcpConn); err != nil { +func (es *ExtendedStats) IncorporateConnectionStats(basicConn net.Conn) error { + if info, err := GetTCPInfo(basicConn); err != nil { return fmt.Errorf("OOPS: Could not get the TCP info for the connection: %v", err) } else { es.MaxPathMtu = utilities.Max(es.MaxPathMtu, uint64(info.Pmtu)) @@ -67,16 +55,21 @@ func (es *ExtendedStats) Repr() string { `, es.MaxPathMtu, es.MaxSendMss, es.MaxRecvMss, es.TotalRetransmissions, es.TotalReorderings, es.AverageRtt) } -func getTCPInfo(connection net.Conn) (*unix.TCPInfo, error) { - tcpConn, ok := connection.(*net.TCPConn) +func GetTCPInfo(basicConn net.Conn) (*unix.TCPInfo, error) { + tlsConn, ok := basicConn.(*tls.Conn) if !ok { - return nil, fmt.Errorf("connection is not a net.TCPConn") + return nil, fmt.Errorf("OOPS: Outermost connection is not a TLS connection") + } + tcpConn, ok := tlsConn.NetConn().(*net.TCPConn) + if !ok { + return nil, fmt.Errorf( + "OOPS: Could not get the TCP info for the connection (not a TCP connection)", + ) } rawConn, err := tcpConn.SyscallConn() if err != nil { return nil, err } - var info *unix.TCPInfo = nil rawConn.Control(func(fd uintptr) { info, err = unix.GetsockoptTCPInfo(int(fd), unix.SOL_TCP, unix.TCP_INFO) @@ -4,7 +4,7 @@ go 1.18 require ( golang.org/x/net v0.0.0-20220225172249-27dd8689420f - golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664 + golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 ) require golang.org/x/text v0.3.7 // indirect @@ -1,8 +1,6 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664 h1:wEZYwx+kK+KlZ0hpvP2Ls1Xr4+RWnlzGFwPP0aiDjIU= -golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= diff --git a/networkQuality.go b/networkQuality.go index f20ca7d..53b2817 100644 --- a/networkQuality.go +++ b/networkQuality.go @@ -406,7 +406,7 @@ func main() { if err := extendedStats.IncorporateConnectionStats(downloadDataCollectionResult.LGCs[i].Stats().ConnInfo.Conn); err != nil { fmt.Fprintf( os.Stderr, - "Warning: Could not add extended stats for the connection: %v", + "Warning: Could not add extended stats for the connection: %v\n", err, ) } @@ -27,6 +27,7 @@ import ( "github.com/network-quality/goresponsiveness/constants" "github.com/network-quality/goresponsiveness/datalogger" "github.com/network-quality/goresponsiveness/debug" + "github.com/network-quality/goresponsiveness/extendedstats" "github.com/network-quality/goresponsiveness/lgc" "github.com/network-quality/goresponsiveness/ma" "github.com/network-quality/goresponsiveness/stats" @@ -63,7 +64,9 @@ type ProbeConfiguration struct { type ProbeDataPoint struct { Time time.Time `Description:"Time of the generation of the data point." Formatter:"Format" FormatterArgument:"01-02-2006-15-04-05.000"` RoundTripCount uint64 `Description:"The number of round trips measured by this data point."` - Duration time.Duration `Description:"The duration for this measurement."` + Duration time.Duration `Description:"The duration for this measurement." Formatter:"Seconds"` + TCPRtt time.Duration `Description:"The underlying connection's RTT at probe time." Formatter:"Seconds"` + TCPCwnd uint32 `Description:"The underlying connection's congestion window at probe time."` } type ThroughputDataPoint struct { @@ -186,7 +189,18 @@ func Probe( ) } }() - dataPoint := ProbeDataPoint{Time: time_before_probe, RoundTripCount: roundTripCount, Duration: totalDelay} + tcpRtt := time.Duration(0 * time.Second) + tcpCwnd := uint32(0) + if extendedstats.ExtendedStatsAvailable() { + tcpInfo, err := extendedstats.GetTCPInfo(probeTracer.stats.ConnInfo.Conn) + if err == nil { + tcpRtt = time.Duration(tcpInfo.Rtt) * time.Microsecond + tcpCwnd = tcpInfo.Snd_cwnd + } else { + fmt.Printf("Warning: Could not fetch the extended stats for a probe: %v\n", err) + } + } + dataPoint := ProbeDataPoint{Time: time_before_probe, RoundTripCount: roundTripCount, Duration: totalDelay, TCPRtt: tcpRtt, TCPCwnd: tcpCwnd} if !utilities.IsInterfaceNil(logger) { logger.LogRecord(dataPoint) } |
