summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Hawkins <[email protected]>2022-08-17 22:07:35 -0400
committerWill Hawkins <[email protected]>2022-08-17 22:07:35 -0400
commit18bcc4fe73bd8245cde001c939b400693a0d9410 (patch)
tree1d38cdb6271153d0bc1ba4ddfc3218722b12ccf7
parent8d7b3f43988f40976c540e64f955fabe3d14d755 (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.go11
-rw-r--r--extendedstats/other.go6
-rw-r--r--extendedstats/unix.go29
-rw-r--r--go.mod2
-rw-r--r--go.sum6
-rw-r--r--networkQuality.go2
-rw-r--r--rpm/rpm.go18
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)
diff --git a/go.mod b/go.mod
index 5fcee76..c017675 100644
--- a/go.mod
+++ b/go.mod
@@ -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
diff --git a/go.sum b/go.sum
index 3fe6d08..75307bd 100644
--- a/go.sum
+++ b/go.sum
@@ -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,
)
}
diff --git a/rpm/rpm.go b/rpm/rpm.go
index 19da8f5..fe8184e 100644
--- a/rpm/rpm.go
+++ b/rpm/rpm.go
@@ -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)
}