summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extendedstats/other.go22
-rw-r--r--extendedstats/unix.go72
-rw-r--r--networkQuality.go54
-rw-r--r--utilities/tcpinfo_other.go18
-rw-r--r--utilities/tcpinfo_unix.go62
-rw-r--r--utilities/utilities.go11
6 files changed, 127 insertions, 112 deletions
diff --git a/extendedstats/other.go b/extendedstats/other.go
new file mode 100644
index 0000000..c0f89ed
--- /dev/null
+++ b/extendedstats/other.go
@@ -0,0 +1,22 @@
+//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd
+// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd
+
+package extendedstats
+
+import (
+ "net"
+
+ "golang.org/x/sys/unix"
+)
+
+type ExtendedStats struct{}
+
+func (es *ExtendedStats) IncorporateConnectionStats(conn net.Conn) {}
+
+func (es *ExtendedStats) Repr() string {
+ return ""
+}
+
+func ExtendedStatsAvailable() bool {
+ return false
+}
diff --git a/extendedstats/unix.go b/extendedstats/unix.go
new file mode 100644
index 0000000..e50d719
--- /dev/null
+++ b/extendedstats/unix.go
@@ -0,0 +1,72 @@
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package extendedstats
+
+import (
+ "crypto/tls"
+ "fmt"
+ "net"
+
+ "github.com/network-quality/goresponsiveness/utilities"
+ "golang.org/x/sys/unix"
+)
+
+type ExtendedStats struct {
+ MaxPathMtu uint64
+ TotalRetransmissions uint64
+ AverageRtt float64
+ rtt_measurements uint64
+ total_rtt float64
+}
+
+func ExtendedStatsAvailable() bool {
+ return true
+}
+
+func (es *ExtendedStats) IncorporateConnectionStats(rawConn net.Conn) {
+ tlsConn, ok := rawConn.(*tls.Conn)
+ if !ok {
+ fmt.Printf("OOPS: Could not get the TCP info for the connection (not a TLS connection)!\n")
+ }
+ tcpConn, ok := tlsConn.NetConn().(*net.TCPConn)
+ if !ok {
+ fmt.Printf("OOPS: Could not get the TCP info for the connection (not a TCP connection)!\n")
+ }
+ if info, err := getTCPInfo(tcpConn); err != nil {
+ fmt.Printf("OOPS: Could not get the TCP info for the connection: %v!\n", err)
+ } else {
+ es.MaxPathMtu = utilities.Max(es.MaxPathMtu, uint64(info.Pmtu))
+ // https://lkml.iu.edu/hypermail/linux/kernel/1705.0/01790.html
+ es.TotalRetransmissions += uint64(info.Total_retrans)
+ es.total_rtt += float64(info.Rtt)
+ es.rtt_measurements += 1
+ es.AverageRtt = es.total_rtt / float64(es.rtt_measurements)
+
+ }
+}
+
+func (es *ExtendedStats) Repr() string {
+ return fmt.Sprintf(`Extended Statistics:
+ Maximum Path MTU: %v
+ Total Retransmissions: %v
+ Average RTT: %v
+`, es.MaxPathMtu, es.TotalRetransmissions, es.AverageRtt)
+}
+
+func getTCPInfo(connection net.Conn) (*unix.TCPInfo, error) {
+ tcpConn, ok := connection.(*net.TCPConn)
+ if !ok {
+ return nil, fmt.Errorf("connection is not a net.TCPConn")
+ }
+ 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)
+ })
+ return info, err
+}
diff --git a/networkQuality.go b/networkQuality.go
index d9bdc94..217ee6a 100644
--- a/networkQuality.go
+++ b/networkQuality.go
@@ -19,9 +19,6 @@ import (
"crypto/tls"
"flag"
"fmt"
- _ "io"
- _ "log"
- "net"
"net/http"
"os"
"runtime/pprof"
@@ -31,6 +28,7 @@ import (
"github.com/network-quality/goresponsiveness/config"
"github.com/network-quality/goresponsiveness/constants"
"github.com/network-quality/goresponsiveness/debug"
+ "github.com/network-quality/goresponsiveness/extendedstats"
"github.com/network-quality/goresponsiveness/lgc"
"github.com/network-quality/goresponsiveness/rpm"
"github.com/network-quality/goresponsiveness/timeoutat"
@@ -80,6 +78,12 @@ var (
"",
"Enable client runtime profiling and specify storage location. Disabled by default.",
)
+
+ calculateExtendedStats = flag.Bool(
+ "extended-stats",
+ false,
+ "Enable the collection and display of extended statistics -- may not be available on certain platforms.",
+ )
)
func main() {
@@ -99,6 +103,11 @@ func main() {
debugLevel = debug.Debug
}
+ if *calculateExtendedStats && !extendedstats.ExtendedStatsAvailable() {
+ *calculateExtendedStats = false
+ fmt.Printf("Warning: Calculation of extended statics was requested but they are not supported on this platform.\n")
+ }
+
if err := config.Get(configHostPort, *configPath); err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
return
@@ -295,6 +304,18 @@ func main() {
totalMeasurements := uint64(0)
totalMeasurementTimes := float64(0)
measurementTimeout := false
+ extendedStats := extendedstats.ExtendedStats{}
+
+ for i := 0; i < len(downloadSaturation.LGCs); i++ {
+ // Assume that extended statistics are available -- the check was done explicitly at
+ // program startup if the calculateExtendedStats flag was set by the user on the command line.
+ if *calculateExtendedStats {
+ if !extendedstats.ExtendedStatsAvailable() {
+ panic("Extended stats are not available but the user requested their calculation.")
+ }
+ extendedStats.IncorporateConnectionStats(downloadSaturation.LGCs[i].Stats().ConnInfo.Conn)
+ }
+ }
for i := 0; i < constants.MeasurementProbeCount && !measurementTimeout; i++ {
if len(downloadSaturation.LGCs) == 0 {
@@ -324,29 +345,6 @@ func main() {
continue
}
- if *debugCliFlag {
- // Note: This code is just an example of how to use utilities.GetTCPInfo.
- rawConn := downloadSaturation.LGCs[randomLGCsIndex].Stats().ConnInfo.Conn
- tlsConn, ok := rawConn.(*tls.Conn)
- if !ok {
- fmt.Printf("OOPS: Could not get the TCP info for the connection (not a TLS connection)!\n")
- }
- tcpConn, ok := tlsConn.NetConn().(*net.TCPConn)
- if !ok {
- fmt.Printf("OOPS: Could not get the TCP info for the connection (not a TCP connection)!\n")
- }
- if info, err := utilities.GetTCPInfo(tcpConn); err != nil {
- switch err.(type) {
- case *utilities.NotImplemented:
- fmt.Printf("GetTCPInfo not implemented on this platform.\n")
- default:
- fmt.Printf("OOPS: Could not get the TCP info for the connection: %v!\n", err)
- }
- } else {
- utilities.PrintTCPInfo(info)
- }
- }
-
unsaturatedMeasurementTransport := http2.Transport{}
unsaturatedMeasurementTransport.TLSClientConfig = &tls.Config{}
if sslKeyFileConcurrentWriter != nil {
@@ -428,6 +426,10 @@ func main() {
fmt.Printf("Error occurred calculating RPM -- no probe measurements received.\n")
}
+ if *calculateExtendedStats {
+ fmt.Printf(extendedStats.Repr())
+ }
+
cancelOperatingCtx()
if *debugCliFlag {
fmt.Printf("In debugging mode, we will cool down.\n")
diff --git a/utilities/tcpinfo_other.go b/utilities/tcpinfo_other.go
deleted file mode 100644
index 8dd070b..0000000
--- a/utilities/tcpinfo_other.go
+++ /dev/null
@@ -1,18 +0,0 @@
-//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd
-// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd
-
-package utilities
-
-import (
- "net"
-
- "golang.org/x/sys/unix"
-)
-
-func GetTCPInfo(connection net.Conn) (*unix.TCPInfo, error) {
- return nil, NotImplemented{Functionality: "GetTCPInfo"}
-}
-
-func PrintTCPInfo(info *unix.TCPInfo) {
- return
-}
diff --git a/utilities/tcpinfo_unix.go b/utilities/tcpinfo_unix.go
deleted file mode 100644
index b0b5252..0000000
--- a/utilities/tcpinfo_unix.go
+++ /dev/null
@@ -1,62 +0,0 @@
-//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd
-// +build darwin dragonfly freebsd linux netbsd openbsd
-
-package utilities
-
-import (
- "fmt"
- "net"
-
- "golang.org/x/sys/unix"
-)
-
-func GetTCPInfo(connection net.Conn) (*unix.TCPInfo, error) {
- tcpConn, ok := connection.(*net.TCPConn)
- if !ok {
- return nil, fmt.Errorf("connection is not a net.TCPConn")
- }
- 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)
- })
- return info, err
-}
-
-func PrintTCPInfo(info *unix.TCPInfo) {
- fmt.Printf("TCPInfo: \n")
- fmt.Printf(" State: %v\n", info.State)
- fmt.Printf(" Ca_state: %v\n", info.Ca_state)
- fmt.Printf(" Retransmits: %v\n", info.Retransmits)
- fmt.Printf(" Probes: %v\n", info.Probes)
- fmt.Printf(" Backoff: %v\n", info.Backoff)
- fmt.Printf(" Options: %v\n", info.Options)
- fmt.Printf(" Rto: %v\n", info.Rto)
- fmt.Printf(" Ato: %v\n", info.Ato)
- fmt.Printf(" Snd_mss: %v\n", info.Snd_mss)
- fmt.Printf(" Rcv_mss: %v\n", info.Rcv_mss)
- fmt.Printf(" Unacked: %v\n", info.Unacked)
- fmt.Printf(" Sacked: %v\n", info.Sacked)
- fmt.Printf(" Lost: %v\n", info.Lost)
- fmt.Printf(" Retrans: %v\n", info.Retrans)
- fmt.Printf(" Fackets: %v\n", info.Fackets)
- fmt.Printf(" Last_data_sent: %v\n", info.Last_data_sent)
- fmt.Printf(" Last_ack_sent: %v\n", info.Last_ack_sent)
- fmt.Printf(" Last_data_recv: %v\n", info.Last_data_recv)
- fmt.Printf(" Last_ack_recv: %v\n", info.Last_ack_recv)
- fmt.Printf(" Pmtu: %v\n", info.Pmtu)
- fmt.Printf(" Rcv_ssthresh: %v\n", info.Rcv_ssthresh)
- fmt.Printf(" Rtt: %v\n", info.Rtt)
- fmt.Printf(" Rttvar: %v\n", info.Rttvar)
- fmt.Printf(" Snd_ssthresh: %v\n", info.Snd_ssthresh)
- fmt.Printf(" Snd_cwnd: %v\n", info.Snd_cwnd)
- fmt.Printf(" Advmss: %v\n", info.Advmss)
- fmt.Printf(" Reordering: %v\n", info.Reordering)
- fmt.Printf(" Rcv_rtt: %v\n", info.Rcv_rtt)
- fmt.Printf(" Rcv_space: %v\n", info.Rcv_space)
- fmt.Printf(" Total_retrans: %v\n", info.Total_retrans)
-}
diff --git a/utilities/utilities.go b/utilities/utilities.go
index 7e26ab9..76acbd2 100644
--- a/utilities/utilities.go
+++ b/utilities/utilities.go
@@ -123,10 +123,9 @@ func RandBetween(max int) int {
return rand.New(rand.NewSource(int64(time.Now().Nanosecond()))).Int() % max
}
-type NotImplemented struct {
- Functionality string
-}
-
-func (ni *NotImplemented) Error() string {
- return fmt.Sprintf("%v not implemented.\n", ni.Functionality)
+func Max(x, y uint64) uint64 {
+ if x > y {
+ return x
+ }
+ return y
}