summaryrefslogtreecommitdiff
path: root/extendedstats/darwin.go
blob: 92e48fca0d813855f6c82fbf74e30490885c6600 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//go:build darwin
// +build darwin

package extendedstats

import (
	"crypto/tls"
	"fmt"
	"net"

	"github.com/network-quality/goresponsiveness/utilities"
	"golang.org/x/sys/unix"
)

type ExtendedStats struct {
	Maxseg               uint64
	MaxSendMss           uint64
	MaxRecvMss           uint64
	TotalRetransmissions uint64
	totalSent            uint64
	TotalReorderings     uint64
	AverageRtt           float64
	rtt_measurements     uint64
	total_rtt            float64
	RetransmitRatio      float64
}

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 := getTCPConnectionInfo(tcpConn); err != nil {
		return fmt.Errorf("OOPS: Could not get the TCP info for the connection: %v", err)
	} else {
		es.Maxseg = utilities.Max(es.Maxseg, uint64(info.Maxseg))
		es.TotalReorderings += info.Rxoutoforderbytes
		es.TotalRetransmissions += info.Txretransmitbytes
		es.totalSent += info.Txbytes
		es.total_rtt += float64(info.Srtt)
		es.rtt_measurements += 1
		es.AverageRtt = es.total_rtt / float64(es.rtt_measurements)
		es.RetransmitRatio = (float64(es.TotalRetransmissions) / float64(es.totalSent)) * 100.0
	}
	return nil
}

func (es *ExtendedStats) Repr() string {
	return fmt.Sprintf(`Extended Statistics:
	Maximum Segment Size: %v
	Total Bytes Retransmitted: %v
	Retransmission Ratio: %.2f%%
	Total Bytes Reordered: %v
	Average RTT: %v
`, es.Maxseg, es.TotalRetransmissions, es.RetransmitRatio, es.TotalReorderings, es.AverageRtt)
}

func getTCPConnectionInfo(connection net.Conn) (*unix.TCPConnectionInfo, 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.TCPConnectionInfo = nil
	rawConn.Control(func(fd uintptr) {
		info, err = unix.GetsockoptTCPConnectionInfo(
			int(fd),
			unix.IPPROTO_TCP,
			unix.TCP_CONNECTION_INFO,
		)
	})
	return info, err
}