├── go.mod ├── .travis.yml ├── .gitignore ├── appveyor.yml ├── README.md ├── defs_freebsd.go ├── defs_netbsd.go ├── sys.go ├── defs_darwin.go ├── example_test.go ├── sys_stub.go ├── zsys_2_6_10_linux.go ├── doc.go ├── zsys_3_19_linux.go ├── zsys_darwin.go ├── LICENSE ├── defs_linux.go ├── option_test.go ├── zsys_freebsd.go ├── zsys_netbsd.go ├── zsys_linux.go ├── tcp.go ├── sys_bsd.go ├── sys_darwin.go ├── option.go └── sys_linux.go /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mikioh/tcpinfo 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | os: 4 | - linux 5 | - osx 6 | 7 | go: 8 | - 1.11.6 9 | - 1.12.1 10 | - tip 11 | 12 | script: 13 | - go test -v -race 14 | 15 | notifications: 16 | email: false 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: "{build}" 2 | 3 | branches: 4 | only: 5 | - master 6 | 7 | environment: 8 | GOPATH: c:\gopath 9 | 10 | install: 11 | - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% 12 | - mkdir c:\gopath 13 | - go get github.com/mikioh/tcp 14 | - go get github.com/mikioh/tcpopt 15 | - go get github.com/mikioh/tcpinfo 16 | 17 | build_script: 18 | - go test -v -race 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Package tcpinfo implements encoding and decoding of TCP-level socket options regarding connection information. 2 | 3 | [![GoDoc](https://godoc.org/github.com/mikioh/tcpinfo?status.png)](https://godoc.org/github.com/mikioh/tcpinfo) 4 | [![Build Status](https://travis-ci.org/mikioh/tcpinfo.svg?branch=master)](https://travis-ci.org/mikioh/tcpinfo) 5 | [![Build status](https://ci.appveyor.com/api/projects/status/7x72aqqg95d3qe57?svg=true)](https://ci.appveyor.com/project/mikioh/tcpinfo) 6 | [![Go Report Card](https://goreportcard.com/badge/github.com/mikioh/tcpinfo)](https://goreportcard.com/report/github.com/mikioh/tcpinfo) 7 | -------------------------------------------------------------------------------- /defs_freebsd.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Mikio Hara. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build ignore 6 | 7 | package tcpinfo 8 | 9 | /* 10 | #include 11 | */ 12 | import "C" 13 | 14 | const ( 15 | sysTCP_INFO = C.TCP_INFO 16 | 17 | sysTCPI_OPT_TIMESTAMPS = C.TCPI_OPT_TIMESTAMPS 18 | sysTCPI_OPT_SACK = C.TCPI_OPT_SACK 19 | sysTCPI_OPT_WSCALE = C.TCPI_OPT_WSCALE 20 | sysTCPI_OPT_ECN = C.TCPI_OPT_ECN 21 | sysTCPI_OPT_TOE = C.TCPI_OPT_TOE 22 | 23 | sizeofTCPInfo = C.sizeof_struct_tcp_info 24 | ) 25 | 26 | type tcpInfo C.struct_tcp_info 27 | -------------------------------------------------------------------------------- /defs_netbsd.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Mikio Hara. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build ignore 6 | 7 | package tcpinfo 8 | 9 | /* 10 | #include 11 | */ 12 | import "C" 13 | 14 | const ( 15 | sysTCP_INFO = C.TCP_INFO 16 | 17 | sysTCPI_OPT_TIMESTAMPS = C.TCPI_OPT_TIMESTAMPS 18 | sysTCPI_OPT_SACK = C.TCPI_OPT_SACK 19 | sysTCPI_OPT_WSCALE = C.TCPI_OPT_WSCALE 20 | sysTCPI_OPT_ECN = C.TCPI_OPT_ECN 21 | sysTCPI_OPT_TOE = C.TCPI_OPT_TOE 22 | 23 | sizeofTCPInfo = C.sizeof_struct_tcp_info 24 | ) 25 | 26 | type tcpInfo C.struct_tcp_info 27 | -------------------------------------------------------------------------------- /sys.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Mikio Hara. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tcpinfo 6 | 7 | import "github.com/mikioh/tcpopt" 8 | 9 | func init() { 10 | for _, o := range options { 11 | if o.name == 0 || o.parseFn == nil { 12 | continue 13 | } 14 | tcpopt.Register(o.level, o.name, o.parseFn) 15 | } 16 | } 17 | 18 | const ( 19 | ianaProtocolTCP = 0x6 20 | ) 21 | 22 | const ( 23 | soInfo = iota 24 | soCCInfo 25 | soCCAlgo 26 | soMax 27 | ) 28 | 29 | // An option represents a binding for socket option. 30 | type option struct { 31 | level int // option level 32 | name int // option name, must be equal or greater than 1 33 | parseFn func([]byte) (tcpopt.Option, error) 34 | } 35 | -------------------------------------------------------------------------------- /defs_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Mikio Hara. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build ignore 6 | 7 | package tcpinfo 8 | 9 | /* 10 | #include 11 | */ 12 | import "C" 13 | 14 | const ( 15 | sysTCP_CONNECTION_INFO = C.TCP_CONNECTION_INFO 16 | 17 | sysTCPCI_OPT_TIMESTAMPS = C.TCPCI_OPT_TIMESTAMPS 18 | sysTCPCI_OPT_SACK = C.TCPCI_OPT_SACK 19 | sysTCPCI_OPT_WSCALE = C.TCPCI_OPT_WSCALE 20 | sysTCPCI_OPT_ECN = C.TCPCI_OPT_ECN 21 | 22 | SysFlagLossRecovery SysFlags = C.TCPCI_FLAG_LOSSRECOVERY 23 | SysFlagReorderingDetected SysFlags = C.TCPCI_FLAG_REORDERING_DETECTED 24 | 25 | sizeofTCPConnectionInfo = C.sizeof_struct_tcp_connection_info 26 | ) 27 | 28 | type tcpConnectionInfo C.struct_tcp_connection_info 29 | -------------------------------------------------------------------------------- /example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Mikio Hara. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tcpinfo_test 6 | 7 | import ( 8 | "encoding/json" 9 | "fmt" 10 | "log" 11 | "net" 12 | 13 | "github.com/mikioh/tcp" 14 | "github.com/mikioh/tcpinfo" 15 | ) 16 | 17 | func ExampleInfo() { 18 | c, err := net.Dial("tcp", "golang.org:80") 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | defer c.Close() 23 | 24 | tc, err := tcp.NewConn(c) 25 | if err != nil { 26 | log.Fatal(err) 27 | } 28 | var o tcpinfo.Info 29 | var b [256]byte 30 | i, err := tc.Option(o.Level(), o.Name(), b[:]) 31 | if err != nil { 32 | log.Fatal(err) 33 | } 34 | txt, err := json.Marshal(i) 35 | if err != nil { 36 | log.Fatal(err) 37 | } 38 | fmt.Println(string(txt)) 39 | } 40 | -------------------------------------------------------------------------------- /sys_stub.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Mikio Hara. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !darwin,!freebsd,!linux,!netbsd 6 | 7 | package tcpinfo 8 | 9 | import ( 10 | "errors" 11 | 12 | "github.com/mikioh/tcpopt" 13 | ) 14 | 15 | var options [soMax]option 16 | 17 | // Marshal implements the Marshal method of tcpopt.Option interface. 18 | func (i *Info) Marshal() ([]byte, error) { 19 | return nil, errors.New("operation not supported") 20 | } 21 | 22 | // A SysInfo represents platform-specific information. 23 | type SysInfo struct{} 24 | 25 | func parseInfo(b []byte) (tcpopt.Option, error) { 26 | return nil, errors.New("operation not supported") 27 | } 28 | 29 | func parseCCAlgorithmInfo(name string, b []byte) (CCAlgorithmInfo, error) { 30 | return nil, errors.New("operation not supported") 31 | } 32 | -------------------------------------------------------------------------------- /zsys_2_6_10_linux.go: -------------------------------------------------------------------------------- 1 | package tcpinfo 2 | 3 | type tcpInfo2_6_10 struct { 4 | State uint8 5 | Ca_state uint8 6 | Retransmits uint8 7 | Probes uint8 8 | Backoff uint8 9 | Options uint8 10 | Pad_cgo_0 [2]byte 11 | Rto uint32 12 | Ato uint32 13 | Snd_mss uint32 14 | Rcv_mss uint32 15 | Unacked uint32 16 | Sacked uint32 17 | Lost uint32 18 | Retrans uint32 19 | Fackets uint32 20 | Last_data_sent uint32 21 | Last_ack_sent uint32 22 | Last_data_recv uint32 23 | Last_ack_recv uint32 24 | Pmtu uint32 25 | Rcv_ssthresh uint32 26 | Rtt uint32 27 | Rttvar uint32 28 | Snd_ssthresh uint32 29 | Snd_cwnd uint32 30 | Advmss uint32 31 | Reordering uint32 32 | Rcv_rtt uint32 33 | Rcv_space uint32 34 | Total_retrans uint32 35 | } 36 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Mikio Hara. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package tcpinfo implements encoding and decoding of TCP-level 6 | // socket options regarding connection information. 7 | // 8 | // The Transmission Control Protocol (TCP) is defined in RFC 793. 9 | // TCP Selective Acknowledgment Options is defined in RFC 2018. 10 | // Management Information Base for the Transmission Control Protocol 11 | // (TCP) is defined in RFC 4022. 12 | // TCP Congestion Control is defined in RFC 5681. 13 | // Computing TCP's Retransmission Timer is described in RFC 6298. 14 | // TCP Options and Maximum Segment Size (MSS) is defined in RFC 6691. 15 | // Shared Use of Experimental TCP Options is defined in RFC 6994. 16 | // TCP Extensions for High Performance is defined in RFC 7323. 17 | // 18 | // NOTE: Older Linux kernels may not support extended TCP statistics 19 | // described in RFC 4898. 20 | package tcpinfo 21 | -------------------------------------------------------------------------------- /zsys_3_19_linux.go: -------------------------------------------------------------------------------- 1 | // Created by cgo -godefs - DO NOT EDIT 2 | // go tool cgo -godefs defs_linux.go 3 | // it was edited to remove duplicated code. Also removed last field (tcpi_last_new_data_recv) 4 | // because we do not use it and getsockopt does not fill it anyway 5 | 6 | package tcpinfo 7 | 8 | type tcpInfo3_19 struct { 9 | State uint8 10 | Ca_state uint8 11 | Retransmits uint8 12 | Probes uint8 13 | Backoff uint8 14 | Options uint8 15 | Pad_cgo_0 [2]byte 16 | Rto uint32 17 | Ato uint32 18 | Snd_mss uint32 19 | Rcv_mss uint32 20 | Unacked uint32 21 | Sacked uint32 22 | Lost uint32 23 | Retrans uint32 24 | Fackets uint32 25 | Last_data_sent uint32 26 | Last_ack_sent uint32 27 | Last_data_recv uint32 28 | Last_ack_recv uint32 29 | Pmtu uint32 30 | Rcv_ssthresh uint32 31 | Rtt uint32 32 | Rttvar uint32 33 | Snd_ssthresh uint32 34 | Snd_cwnd uint32 35 | Advmss uint32 36 | Reordering uint32 37 | Rcv_rtt uint32 38 | Rcv_space uint32 39 | Total_retrans uint32 40 | Pacing_rate uint64 41 | Max_pacing_rate uint64 42 | } 43 | -------------------------------------------------------------------------------- /zsys_darwin.go: -------------------------------------------------------------------------------- 1 | // Created by cgo -godefs - DO NOT EDIT 2 | // cgo -godefs defs_darwin.go 3 | 4 | package tcpinfo 5 | 6 | const ( 7 | sysTCP_CONNECTION_INFO = 0x106 8 | 9 | sysTCPCI_OPT_TIMESTAMPS = 0x1 10 | sysTCPCI_OPT_SACK = 0x2 11 | sysTCPCI_OPT_WSCALE = 0x4 12 | sysTCPCI_OPT_ECN = 0x8 13 | 14 | SysFlagLossRecovery SysFlags = 0x1 15 | SysFlagReorderingDetected SysFlags = 0x2 16 | 17 | sizeofTCPConnectionInfo = 0x70 18 | ) 19 | 20 | type tcpConnectionInfo struct { 21 | State uint8 22 | Snd_wscale uint8 23 | Rcv_wscale uint8 24 | X__pad1 uint8 25 | Options uint32 26 | Flags uint32 27 | Rto uint32 28 | Maxseg uint32 29 | Snd_ssthresh uint32 30 | Snd_cwnd uint32 31 | Snd_wnd uint32 32 | Snd_sbbytes uint32 33 | Rcv_wnd uint32 34 | Rttcur uint32 35 | Srtt uint32 36 | Rttvar uint32 37 | Pad_cgo_0 [4]byte 38 | Txpackets uint64 39 | Txbytes uint64 40 | Txretransmitbytes uint64 41 | Rxpackets uint64 42 | Rxbytes uint64 43 | Rxoutoforderbytes uint64 44 | Txretransmitpackets uint64 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Mikio Hara 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /defs_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Mikio Hara. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build ignore 6 | 7 | package tcpinfo 8 | 9 | /* 10 | #include 11 | #include 12 | #include 13 | */ 14 | import "C" 15 | 16 | const ( 17 | sysTCP_INFO = C.TCP_INFO 18 | sysTCP_CONGESTION = C.TCP_CONGESTION 19 | sysTCP_CC_INFO = C.TCP_CC_INFO 20 | 21 | sysTCPI_OPT_TIMESTAMPS = C.TCPI_OPT_TIMESTAMPS 22 | sysTCPI_OPT_SACK = C.TCPI_OPT_SACK 23 | sysTCPI_OPT_WSCALE = C.TCPI_OPT_WSCALE 24 | sysTCPI_OPT_ECN = C.TCPI_OPT_ECN 25 | sysTCPI_OPT_ECN_SEEN = C.TCPI_OPT_ECN_SEEN 26 | sysTCPI_OPT_SYN_DATA = C.TCPI_OPT_SYN_DATA 27 | 28 | CAOpen CAState = C.TCP_CA_Open 29 | CADisorder CAState = C.TCP_CA_Disorder 30 | CACWR CAState = C.TCP_CA_CWR 31 | CARecovery CAState = C.TCP_CA_Recovery 32 | CALoss CAState = C.TCP_CA_Loss 33 | 34 | sizeofTCPInfo = C.sizeof_struct_tcp_info 35 | sizeofTCPCCInfo = C.sizeof_union_tcp_cc_info 36 | sizeofTCPVegasInfo = C.sizeof_struct_tcpvegas_info 37 | sizeofTCPDCTCPInfo = C.sizeof_struct_tcp_dctcp_info 38 | sizeofTCPBBRInfo = C.sizeof_struct_tcp_bbr_info 39 | ) 40 | 41 | type tcpInfo C.struct_tcp_info 42 | 43 | type tcpCCInfo C.union_tcp_cc_info 44 | 45 | type tcpVegasInfo C.struct_tcpvegas_info 46 | 47 | type tcpDCTCPInfo C.struct_tcp_dctcp_info 48 | 49 | type tcpBBRInfo C.struct_tcp_bbr_info 50 | -------------------------------------------------------------------------------- /option_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Mikio Hara. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tcpinfo_test 6 | 7 | import ( 8 | "runtime" 9 | "testing" 10 | 11 | "github.com/mikioh/tcpinfo" 12 | "github.com/mikioh/tcpopt" 13 | ) 14 | 15 | func TestMarshalAndParse(t *testing.T) { 16 | opts := make([]tcpopt.Option, 0, 3) 17 | switch runtime.GOOS { 18 | case "darwin", "freebsd", "netbsd": 19 | opts = append(opts, &tcpinfo.Info{}) 20 | case "linux": 21 | opts = append(opts, &tcpinfo.Info{}) 22 | opts = append(opts, &tcpinfo.CCInfo{}) 23 | opts = append(opts, tcpinfo.CCAlgorithm("vegas")) 24 | default: 25 | t.Skipf("%s/%s", runtime.GOOS, runtime.GOARCH) 26 | } 27 | 28 | for _, o := range opts { 29 | if o.Level() <= 0 { 30 | t.Fatalf("got %#x; want greater than zero", o.Level()) 31 | } 32 | if o.Name() <= 0 { 33 | t.Fatalf("got %#x; want greater than zero", o.Name()) 34 | } 35 | b, err := o.Marshal() 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | if len(b) == 0 { 40 | continue 41 | } 42 | oo, err := tcpopt.Parse(o.Level(), o.Name(), b) 43 | if err != nil { 44 | t.Fatal(err) 45 | } 46 | if oo, ok := oo.(*tcpinfo.Info); ok { 47 | if _, err := oo.MarshalJSON(); err != nil { 48 | t.Fatal(err) 49 | } 50 | } 51 | } 52 | } 53 | 54 | func TestParseWithVariousBufferLengths(t *testing.T) { 55 | for _, o := range []tcpopt.Option{ 56 | &tcpinfo.Info{}, 57 | &tcpinfo.CCInfo{}, 58 | tcpinfo.CCAlgorithm("vegas"), 59 | } { 60 | for i := 0; i < 256; i++ { 61 | b := make([]byte, i) 62 | if _, err := tcpopt.Parse(o.Level(), o.Name(), b); err == nil { 63 | break 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /zsys_freebsd.go: -------------------------------------------------------------------------------- 1 | // Created by cgo -godefs - DO NOT EDIT 2 | // cgo -godefs defs_freebsd.go 3 | 4 | package tcpinfo 5 | 6 | const ( 7 | sysTCP_INFO = 0x20 8 | 9 | sysTCPI_OPT_TIMESTAMPS = 0x1 10 | sysTCPI_OPT_SACK = 0x2 11 | sysTCPI_OPT_WSCALE = 0x4 12 | sysTCPI_OPT_ECN = 0x8 13 | sysTCPI_OPT_TOE = 0x10 14 | 15 | sizeofTCPInfo = 0xec 16 | ) 17 | 18 | type tcpInfo struct { 19 | State uint8 20 | X__tcpi_ca_state uint8 21 | X__tcpi_retransmits uint8 22 | X__tcpi_probes uint8 23 | X__tcpi_backoff uint8 24 | Options uint8 25 | Pad_cgo_0 [2]byte 26 | Rto uint32 27 | X__tcpi_ato uint32 28 | Snd_mss uint32 29 | Rcv_mss uint32 30 | X__tcpi_unacked uint32 31 | X__tcpi_sacked uint32 32 | X__tcpi_lost uint32 33 | X__tcpi_retrans uint32 34 | X__tcpi_fackets uint32 35 | X__tcpi_last_data_sent uint32 36 | X__tcpi_last_ack_sent uint32 37 | Last_data_recv uint32 38 | X__tcpi_last_ack_recv uint32 39 | X__tcpi_pmtu uint32 40 | X__tcpi_rcv_ssthresh uint32 41 | Rtt uint32 42 | Rttvar uint32 43 | Snd_ssthresh uint32 44 | Snd_cwnd uint32 45 | X__tcpi_advmss uint32 46 | X__tcpi_reordering uint32 47 | X__tcpi_rcv_rtt uint32 48 | Rcv_space uint32 49 | Snd_wnd uint32 50 | Snd_bwnd uint32 51 | Snd_nxt uint32 52 | Rcv_nxt uint32 53 | Toe_tid uint32 54 | Snd_rexmitpack uint32 55 | Rcv_ooopack uint32 56 | Snd_zerowin uint32 57 | X__tcpi_pad [26]uint32 58 | } 59 | -------------------------------------------------------------------------------- /zsys_netbsd.go: -------------------------------------------------------------------------------- 1 | // Created by cgo -godefs - DO NOT EDIT 2 | // cgo -godefs defs_netbsd.go 3 | 4 | package tcpinfo 5 | 6 | const ( 7 | sysTCP_INFO = 0x9 8 | 9 | sysTCPI_OPT_TIMESTAMPS = 0x1 10 | sysTCPI_OPT_SACK = 0x2 11 | sysTCPI_OPT_WSCALE = 0x4 12 | sysTCPI_OPT_ECN = 0x8 13 | sysTCPI_OPT_TOE = 0x10 14 | 15 | sizeofTCPInfo = 0xec 16 | ) 17 | 18 | type tcpInfo struct { 19 | State uint8 20 | X__tcpi_ca_state uint8 21 | X__tcpi_retransmits uint8 22 | X__tcpi_probes uint8 23 | X__tcpi_backoff uint8 24 | Options uint8 25 | Pad_cgo_0 [2]byte 26 | Rto uint32 27 | X__tcpi_ato uint32 28 | Snd_mss uint32 29 | Rcv_mss uint32 30 | X__tcpi_unacked uint32 31 | X__tcpi_sacked uint32 32 | X__tcpi_lost uint32 33 | X__tcpi_retrans uint32 34 | X__tcpi_fackets uint32 35 | X__tcpi_last_data_sent uint32 36 | X__tcpi_last_ack_sent uint32 37 | Last_data_recv uint32 38 | X__tcpi_last_ack_recv uint32 39 | X__tcpi_pmtu uint32 40 | X__tcpi_rcv_ssthresh uint32 41 | Rtt uint32 42 | Rttvar uint32 43 | Snd_ssthresh uint32 44 | Snd_cwnd uint32 45 | X__tcpi_advmss uint32 46 | X__tcpi_reordering uint32 47 | X__tcpi_rcv_rtt uint32 48 | Rcv_space uint32 49 | Snd_wnd uint32 50 | Snd_bwnd uint32 51 | Snd_nxt uint32 52 | Rcv_nxt uint32 53 | Toe_tid uint32 54 | Snd_rexmitpack uint32 55 | Rcv_ooopack uint32 56 | Snd_zerowin uint32 57 | X__tcpi_pad [26]uint32 58 | } 59 | -------------------------------------------------------------------------------- /zsys_linux.go: -------------------------------------------------------------------------------- 1 | // Created by cgo -godefs - DO NOT EDIT 2 | // cgo -godefs defs_linux.go 3 | 4 | package tcpinfo 5 | 6 | const ( 7 | sysTCP_INFO = 0xb 8 | sysTCP_CONGESTION = 0xd 9 | sysTCP_CC_INFO = 0x1a 10 | 11 | sysTCPI_OPT_TIMESTAMPS = 0x1 12 | sysTCPI_OPT_SACK = 0x2 13 | sysTCPI_OPT_WSCALE = 0x4 14 | sysTCPI_OPT_ECN = 0x8 15 | sysTCPI_OPT_ECN_SEEN = 0x10 16 | sysTCPI_OPT_SYN_DATA = 0x20 17 | 18 | CAOpen CAState = 0x0 19 | CADisorder CAState = 0x1 20 | CACWR CAState = 0x2 21 | CARecovery CAState = 0x3 22 | CALoss CAState = 0x4 23 | 24 | sizeofTCPInfo = 0xc0 25 | sizeofTCPCCInfo = 0x14 26 | sizeofTCPVegasInfo = 0x10 27 | sizeofTCPDCTCPInfo = 0x10 28 | sizeofTCPBBRInfo = 0x14 29 | ) 30 | 31 | type tcpInfo struct { 32 | State uint8 33 | Ca_state uint8 34 | Retransmits uint8 35 | Probes uint8 36 | Backoff uint8 37 | Options uint8 38 | Pad_cgo_0 [1]byte 39 | Pad_cgo_1 [1]byte 40 | Rto uint32 41 | Ato uint32 42 | Snd_mss uint32 43 | Rcv_mss uint32 44 | Unacked uint32 45 | Sacked uint32 46 | Lost uint32 47 | Retrans uint32 48 | Fackets uint32 49 | Last_data_sent uint32 50 | Last_ack_sent uint32 51 | Last_data_recv uint32 52 | Last_ack_recv uint32 53 | Pmtu uint32 54 | Rcv_ssthresh uint32 55 | Rtt uint32 56 | Rttvar uint32 57 | Snd_ssthresh uint32 58 | Snd_cwnd uint32 59 | Advmss uint32 60 | Reordering uint32 61 | Rcv_rtt uint32 62 | Rcv_space uint32 63 | Total_retrans uint32 64 | Pacing_rate uint64 65 | Max_pacing_rate uint64 66 | Bytes_acked uint64 67 | Bytes_received uint64 68 | Segs_out uint32 69 | Segs_in uint32 70 | Notsent_bytes uint32 71 | Min_rtt uint32 72 | Data_segs_in uint32 73 | Data_segs_out uint32 74 | Delivery_rate uint64 75 | Busy_time uint64 76 | Rwnd_limited uint64 77 | Sndbuf_limited uint64 78 | } 79 | 80 | type tcpCCInfo [20]byte 81 | 82 | type tcpVegasInfo struct { 83 | Enabled uint32 84 | Rttcnt uint32 85 | Rtt uint32 86 | Minrtt uint32 87 | } 88 | 89 | type tcpDCTCPInfo struct { 90 | Enabled uint16 91 | Ce_state uint16 92 | Alpha uint32 93 | Ab_ecn uint32 94 | Ab_tot uint32 95 | } 96 | 97 | type tcpBBRInfo struct { 98 | Bw_lo uint32 99 | Bw_hi uint32 100 | Min_rtt uint32 101 | Pacing_gain uint32 102 | Cwnd_gain uint32 103 | } 104 | -------------------------------------------------------------------------------- /tcp.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Mikio Hara. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tcpinfo 6 | 7 | // A State represents a state of connection. 8 | type State int 9 | 10 | const ( 11 | Unknown State = iota 12 | Closed 13 | Listen 14 | SynSent 15 | SynReceived 16 | Established 17 | FinWait1 18 | FinWait2 19 | CloseWait 20 | LastAck 21 | Closing 22 | TimeWait 23 | ) 24 | 25 | var states = map[State]string{ 26 | Unknown: "unknown", 27 | Closed: "closed", 28 | Listen: "listen", 29 | SynSent: "syn-sent", 30 | SynReceived: "syn-received", 31 | Established: "established", 32 | FinWait1: "fin-wait-1", 33 | FinWait2: "fin-wait-2", 34 | CloseWait: "close-wait", 35 | LastAck: "last-ack", 36 | Closing: "closing", 37 | TimeWait: "time-wait", 38 | } 39 | 40 | func (st State) String() string { 41 | s, ok := states[st] 42 | if !ok { 43 | return "" 44 | } 45 | return s 46 | } 47 | 48 | // An OptionKind represents an option kind. 49 | type OptionKind int 50 | 51 | const ( 52 | KindMaxSegSize OptionKind = 2 53 | KindWindowScale OptionKind = 3 54 | KindSACKPermitted OptionKind = 4 55 | KindTimestamps OptionKind = 8 56 | ) 57 | 58 | var optionKinds = map[OptionKind]string{ 59 | KindMaxSegSize: "mss", 60 | KindWindowScale: "wscale", 61 | KindSACKPermitted: "sack", 62 | KindTimestamps: "tmstamps", 63 | } 64 | 65 | func (k OptionKind) String() string { 66 | s, ok := optionKinds[k] 67 | if !ok { 68 | return "" 69 | } 70 | return s 71 | } 72 | 73 | // An Option represents an option. 74 | type Option interface { 75 | Kind() OptionKind 76 | } 77 | 78 | // A MaxSegSize represents a maxiumum segment size option. 79 | type MaxSegSize uint 80 | 81 | // Kind returns an option kind field. 82 | func (mss MaxSegSize) Kind() OptionKind { return KindMaxSegSize } 83 | 84 | // A WindowScale represents a windows scale option. 85 | type WindowScale int 86 | 87 | // Kind returns an option kind field. 88 | func (ws WindowScale) Kind() OptionKind { return KindWindowScale } 89 | 90 | // A SACKPermitted reports whether a selective acknowledgment 91 | // permitted option is enabled. 92 | type SACKPermitted bool 93 | 94 | // Kind returns an option kind field. 95 | func (sp SACKPermitted) Kind() OptionKind { return KindSACKPermitted } 96 | 97 | // A Timestamps reports whether a timestamps option is enabled. 98 | type Timestamps bool 99 | 100 | // Kind returns an option kind field. 101 | func (ts Timestamps) Kind() OptionKind { return KindTimestamps } 102 | -------------------------------------------------------------------------------- /sys_bsd.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Mikio Hara. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build freebsd netbsd 6 | 7 | package tcpinfo 8 | 9 | import ( 10 | "errors" 11 | "runtime" 12 | "time" 13 | "unsafe" 14 | 15 | "github.com/mikioh/tcpopt" 16 | ) 17 | 18 | var options = [soMax]option{ 19 | soInfo: {ianaProtocolTCP, sysTCP_INFO, parseInfo}, 20 | } 21 | 22 | // Marshal implements the Marshal method of tcpopt.Option interface. 23 | func (i *Info) Marshal() ([]byte, error) { return (*[sizeofTCPInfo]byte)(unsafe.Pointer(i))[:], nil } 24 | 25 | // A SysInfo represents platform-specific information. 26 | type SysInfo struct { 27 | SenderWindowBytes uint `json:"snd_wnd_bytes"` // advertised sender window in bytes [FreeBSD] 28 | SenderWindowSegs uint `json:"snd_wnd_segs"` // advertised sender window in # of segments [NetBSD] 29 | NextEgressSeq uint `json:"egress_seq"` // next egress seq. number 30 | NextIngressSeq uint `json:"ingress_seq"` // next ingress seq. number 31 | RetransSegs uint `json:"retrans_segs"` // # of retransmit segments sent 32 | OutOfOrderSegs uint `json:"ooo_segs"` // # of out-of-order segments received 33 | ZeroWindowUpdates uint `json:"zerownd_updates"` // # of zero-window updates sent 34 | Offloading bool `json:"offloading"` // TCP offload processing 35 | } 36 | 37 | var sysStates = [11]State{Closed, Listen, SynSent, SynReceived, Established, CloseWait, FinWait1, Closing, LastAck, FinWait2, TimeWait} 38 | 39 | func parseInfo(b []byte) (tcpopt.Option, error) { 40 | if len(b) < sizeofTCPInfo { 41 | return nil, errors.New("short buffer") 42 | } 43 | ti := (*tcpInfo)(unsafe.Pointer(&b[0])) 44 | i := &Info{State: sysStates[ti.State]} 45 | if ti.Options&sysTCPI_OPT_WSCALE != 0 { 46 | i.Options = append(i.Options, WindowScale(ti.Pad_cgo_0[0]>>4)) 47 | i.PeerOptions = append(i.PeerOptions, WindowScale(ti.Pad_cgo_0[0]&0x0f)) 48 | } 49 | if ti.Options&sysTCPI_OPT_SACK != 0 { 50 | i.Options = append(i.Options, SACKPermitted(true)) 51 | i.PeerOptions = append(i.PeerOptions, SACKPermitted(true)) 52 | } 53 | if ti.Options&sysTCPI_OPT_TIMESTAMPS != 0 { 54 | i.Options = append(i.Options, Timestamps(true)) 55 | i.PeerOptions = append(i.PeerOptions, Timestamps(true)) 56 | } 57 | i.SenderMSS = MaxSegSize(ti.Snd_mss) 58 | i.ReceiverMSS = MaxSegSize(ti.Rcv_mss) 59 | i.RTT = time.Duration(ti.Rtt) * time.Microsecond 60 | i.RTTVar = time.Duration(ti.Rttvar) * time.Microsecond 61 | i.RTO = time.Duration(ti.Rto) * time.Microsecond 62 | i.ATO = time.Duration(ti.X__tcpi_ato) * time.Microsecond 63 | i.LastDataSent = time.Duration(ti.X__tcpi_last_data_sent) * time.Microsecond 64 | i.LastDataReceived = time.Duration(ti.Last_data_recv) * time.Microsecond 65 | i.LastAckReceived = time.Duration(ti.X__tcpi_last_ack_recv) * time.Microsecond 66 | i.FlowControl = &FlowControl{ 67 | ReceiverWindow: uint(ti.Rcv_space), 68 | } 69 | i.CongestionControl = &CongestionControl{ 70 | SenderSSThreshold: uint(ti.Snd_ssthresh), 71 | ReceiverSSThreshold: uint(ti.X__tcpi_rcv_ssthresh), 72 | } 73 | i.Sys = &SysInfo{ 74 | NextEgressSeq: uint(ti.Snd_nxt), 75 | NextIngressSeq: uint(ti.Rcv_nxt), 76 | RetransSegs: uint(ti.Snd_rexmitpack), 77 | OutOfOrderSegs: uint(ti.Rcv_ooopack), 78 | ZeroWindowUpdates: uint(ti.Snd_zerowin), 79 | } 80 | if ti.Options&sysTCPI_OPT_TOE != 0 { 81 | i.Sys.Offloading = true 82 | } 83 | switch runtime.GOOS { 84 | case "freebsd": 85 | i.CongestionControl.SenderWindowBytes = uint(ti.Snd_cwnd) 86 | i.Sys.SenderWindowBytes = uint(ti.Snd_wnd) 87 | case "netbsd": 88 | i.CongestionControl.SenderWindowSegs = uint(ti.Snd_cwnd) 89 | i.Sys.SenderWindowSegs = uint(ti.Snd_wnd) 90 | } 91 | return i, nil 92 | } 93 | 94 | func parseCCAlgorithmInfo(name string, b []byte) (CCAlgorithmInfo, error) { 95 | return nil, errors.New("operation not supported") 96 | } 97 | -------------------------------------------------------------------------------- /sys_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Mikio Hara. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tcpinfo 6 | 7 | import ( 8 | "errors" 9 | "time" 10 | "unsafe" 11 | 12 | "github.com/mikioh/tcpopt" 13 | ) 14 | 15 | var options = [soMax]option{ 16 | soInfo: {ianaProtocolTCP, sysTCP_CONNECTION_INFO, parseInfo}, 17 | } 18 | 19 | // Marshal implements the Marshal method of tcpopt.Option interface. 20 | func (i *Info) Marshal() ([]byte, error) { 21 | return (*[sizeofTCPConnectionInfo]byte)(unsafe.Pointer(i))[:], nil 22 | } 23 | 24 | type SysFlags uint 25 | 26 | func (f SysFlags) String() string { 27 | s := "" 28 | for i, name := range []string{ 29 | "loss recovery", 30 | "reordering detected", 31 | } { 32 | if f&(1< sizeofTCPConnectionInfoV15 { 107 | i.Sys.RetransSegs = uint64(tci.Txretransmitpackets) 108 | } 109 | return i, nil 110 | } 111 | 112 | func parseCCAlgorithmInfo(name string, b []byte) (CCAlgorithmInfo, error) { 113 | return nil, errors.New("operation not supported") 114 | } 115 | -------------------------------------------------------------------------------- /option.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Mikio Hara. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tcpinfo 6 | 7 | import ( 8 | "encoding/json" 9 | "time" 10 | 11 | "github.com/mikioh/tcpopt" 12 | ) 13 | 14 | var ( 15 | _ json.Marshaler = &Info{} 16 | _ tcpopt.Option = &Info{} 17 | ) 18 | 19 | // An Info represents connection information. 20 | // 21 | // Only supported on Darwin, FreeBSD, Linux and NetBSD. 22 | type Info struct { 23 | State State `json:"state"` // connection state 24 | Options []Option `json:"opts,omitempty"` // requesting options 25 | PeerOptions []Option `json:"peer_opts,omitempty"` // options requested from peer 26 | SenderMSS MaxSegSize `json:"snd_mss"` // maximum segment size for sender in bytes 27 | ReceiverMSS MaxSegSize `json:"rcv_mss"` // maximum segment size for receiver in bytes 28 | RTT time.Duration `json:"rtt"` // round-trip time 29 | RTTVar time.Duration `json:"rttvar"` // round-trip time variation 30 | RTO time.Duration `json:"rto"` // retransmission timeout 31 | ATO time.Duration `json:"ato"` // delayed acknowledgement timeout [Linux only] 32 | LastDataSent time.Duration `json:"last_data_sent"` // since last data sent [Linux only] 33 | LastDataReceived time.Duration `json:"last_data_rcvd"` // since last data received [FreeBSD and Linux] 34 | LastAckReceived time.Duration `json:"last_ack_rcvd"` // since last ack received [Linux only] 35 | FlowControl *FlowControl `json:"flow_ctl,omitempty"` // flow control information 36 | CongestionControl *CongestionControl `json:"cong_ctl,omitempty"` // congestion control information 37 | Sys *SysInfo `json:"sys,omitempty"` // platform-specific information 38 | } 39 | 40 | // A FlowControl represents flow control information. 41 | type FlowControl struct { 42 | ReceiverWindow uint `json:"rcv_wnd"` // advertised receiver window in bytes 43 | } 44 | 45 | // A CongestionControl represents congestion control information. 46 | type CongestionControl struct { 47 | SenderSSThreshold uint `json:"snd_ssthresh"` // slow start threshold for sender in bytes or # of segments 48 | ReceiverSSThreshold uint `json:"rcv_ssthresh"` // slow start threshold for receiver in bytes [Linux only] 49 | SenderWindowBytes uint `json:"snd_cwnd_bytes"` // congestion window for sender in bytes [Darwin and FreeBSD] 50 | SenderWindowSegs uint `json:"snd_cwnd_segs"` // congestion window for sender in # of segments [Linux and NetBSD] 51 | } 52 | 53 | // Level implements the Level method of tcpopt.Option interface. 54 | func (i *Info) Level() int { return options[soInfo].level } 55 | 56 | // Name implements the Name method of tcpopt.Option interface. 57 | func (i *Info) Name() int { return options[soInfo].name } 58 | 59 | // MarshalJSON implements the MarshalJSON method of json.Marshaler 60 | // interface. 61 | func (i *Info) MarshalJSON() ([]byte, error) { 62 | raw := make(map[string]interface{}) 63 | raw["state"] = i.State.String() 64 | if len(i.Options) > 0 { 65 | opts := make(map[string]interface{}) 66 | for _, opt := range i.Options { 67 | opts[opt.Kind().String()] = opt 68 | } 69 | raw["opts"] = opts 70 | } 71 | if len(i.PeerOptions) > 0 { 72 | opts := make(map[string]interface{}) 73 | for _, opt := range i.PeerOptions { 74 | opts[opt.Kind().String()] = opt 75 | } 76 | raw["peer_opts"] = opts 77 | } 78 | raw["snd_mss"] = i.SenderMSS 79 | raw["rcv_mss"] = i.ReceiverMSS 80 | raw["rtt"] = i.RTT 81 | raw["rttvar"] = i.RTTVar 82 | raw["rto"] = i.RTO 83 | raw["ato"] = i.ATO 84 | raw["last_data_sent"] = i.LastDataSent 85 | raw["last_data_rcvd"] = i.LastDataReceived 86 | raw["last_ack_rcvd"] = i.LastAckReceived 87 | if i.FlowControl != nil { 88 | raw["flow_ctl"] = i.FlowControl 89 | } 90 | if i.CongestionControl != nil { 91 | raw["cong_ctl"] = i.CongestionControl 92 | } 93 | if i.Sys != nil { 94 | raw["sys"] = i.Sys 95 | } 96 | return json.Marshal(&raw) 97 | } 98 | 99 | // A CCInfo represents raw information of congestion control 100 | // algorithm. 101 | // 102 | // Only supported on Linux. 103 | type CCInfo struct { 104 | Raw []byte `json:"raw,omitempty"` 105 | } 106 | 107 | // Level implements the Level method of tcpopt.Option interface. 108 | func (cci *CCInfo) Level() int { return options[soCCInfo].level } 109 | 110 | // Name implements the Name method of tcpopt.Option interface. 111 | func (cci *CCInfo) Name() int { return options[soCCInfo].name } 112 | 113 | // Marshal implements the Marshal method of tcpopt.Option interface. 114 | func (cci *CCInfo) Marshal() ([]byte, error) { return cci.Raw, nil } 115 | 116 | func parseCCInfo(b []byte) (tcpopt.Option, error) { return &CCInfo{Raw: b}, nil } 117 | 118 | // A CCAlgorithm represents a name of congestion control algorithm. 119 | // 120 | // Only supported on Linux. 121 | type CCAlgorithm string 122 | 123 | // Level implements the Level method of tcpopt.Option interface. 124 | func (cca CCAlgorithm) Level() int { return options[soCCAlgo].level } 125 | 126 | // Name implements the Name method of tcpopt.Option interface. 127 | func (cca CCAlgorithm) Name() int { return options[soCCAlgo].name } 128 | 129 | // Marshal implements the Marshal method of tcpopt.Option interface. 130 | func (cca CCAlgorithm) Marshal() ([]byte, error) { 131 | if cca == "" { 132 | return nil, nil 133 | } 134 | return []byte(cca), nil 135 | } 136 | 137 | func parseCCAlgorithm(b []byte) (tcpopt.Option, error) { return CCAlgorithm(b), nil } 138 | 139 | // A CCAlgorithmInfo represents congestion control algorithm 140 | // information. 141 | // 142 | // Only supported on Linux. 143 | type CCAlgorithmInfo interface { 144 | Algorithm() string 145 | } 146 | 147 | // ParseCCAlgorithmInfo parses congestion control algorithm 148 | // information. 149 | // 150 | // Only supported on Linux. 151 | func ParseCCAlgorithmInfo(name string, b []byte) (CCAlgorithmInfo, error) { 152 | ccai, err := parseCCAlgorithmInfo(name, b) 153 | if err != nil { 154 | return nil, err 155 | } 156 | return ccai, nil 157 | } 158 | -------------------------------------------------------------------------------- /sys_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Mikio Hara. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tcpinfo 6 | 7 | import ( 8 | "errors" 9 | "strings" 10 | "time" 11 | "unsafe" 12 | 13 | "github.com/mikioh/tcpopt" 14 | ) 15 | 16 | var options = [soMax]option{ 17 | soInfo: {ianaProtocolTCP, sysTCP_INFO, parseInfo}, 18 | soCCInfo: {ianaProtocolTCP, sysTCP_CC_INFO, parseCCInfo}, 19 | soCCAlgo: {ianaProtocolTCP, sysTCP_CONGESTION, parseCCAlgorithm}, 20 | } 21 | 22 | // Marshal implements the Marshal method of tcpopt.Option interface. 23 | func (i *Info) Marshal() ([]byte, error) { return (*[sizeofTCPInfo]byte)(unsafe.Pointer(i))[:], nil } 24 | 25 | // A CAState represents a state of congestion avoidance. 26 | type CAState int 27 | 28 | var caStates = map[CAState]string{ 29 | CAOpen: "open", 30 | CADisorder: "disorder", 31 | CACWR: "congestion window reduced", 32 | CARecovery: "recovery", 33 | CALoss: "loss", 34 | } 35 | 36 | func (st CAState) String() string { 37 | s, ok := caStates[st] 38 | if !ok { 39 | return "" 40 | } 41 | return s 42 | } 43 | 44 | // A SysInfo represents platform-specific information. 45 | type SysInfo struct { 46 | PathMTU uint `json:"path_mtu"` // path maximum transmission unit 47 | AdvertisedMSS MaxSegSize `json:"adv_mss"` // advertised maximum segment size 48 | CAState CAState `json:"ca_state"` // state of congestion avoidance 49 | Retransmissions uint `json:"rexmits"` // # of retranmissions on timeout invoked 50 | Backoffs uint `json:"backoffs"` // # of times retransmission backoff timer invoked 51 | WindowOrKeepAliveProbes uint `json:"wnd_ka_probes"` // # of window or keep alive probes sent 52 | UnackedSegs uint `json:"unacked_segs"` // # of unack'd segments 53 | SackedSegs uint `json:"sacked_segs"` // # of sack'd segments 54 | LostSegs uint `json:"lost_segs"` // # of lost segments 55 | RetransSegs uint `json:"retrans_segs"` // # of retransmitting segments in transmission queue 56 | ForwardAckSegs uint `json:"fack_segs"` // # of forward ack segments in transmission queue 57 | ReorderedSegs uint `json:"reord_segs"` // # of reordered segments allowed 58 | ReceiverRTT time.Duration `json:"rcv_rtt"` // current RTT for receiver 59 | TotalRetransSegs uint `json:"total_retrans_segs"` // # of retransmitted segments 60 | PacingRate uint64 `json:"pacing_rate"` // pacing rate 61 | ThruBytesAcked uint64 `json:"thru_bytes_acked"` // # of bytes for which cumulative acknowledgments have been received 62 | ThruBytesReceived uint64 `json:"thru_bytes_rcvd"` // # of bytes for which cumulative acknowledgments have been sent 63 | SegsOut uint `json:"segs_out"` // # of segments sent 64 | SegsIn uint `json:"segs_in"` // # of segments received 65 | NotSentBytes uint `json:"not_sent_bytes"` // # of bytes not sent yet 66 | MinRTT time.Duration `json:"min_rtt"` // current measured minimum RTT; zero means not available 67 | DataSegsOut uint `json:"data_segs_out"` // # of segments sent containing a positive length data segment 68 | DataSegsIn uint `json:"data_segs_in"` // # of segments received containing a positive length data segment 69 | } 70 | 71 | var sysStates = [12]State{Unknown, Established, SynSent, SynReceived, FinWait1, FinWait2, TimeWait, Closed, CloseWait, LastAck, Listen, Closing} 72 | 73 | const ( 74 | sizeofTCPInfoV4_9 = 0xa0 75 | sizeofTCPInfoV3_19 = 0x78 76 | sizeofTCPInfoV2_6_10 = 0x57 77 | ) 78 | 79 | func parseInfo(b []byte) (tcpopt.Option, error) { 80 | if len(b) < sizeofTCPInfoV4_9 { 81 | return parseInfo3_19(b) 82 | } 83 | ti := (*tcpInfo)(unsafe.Pointer(&b[0])) 84 | i := &Info{State: sysStates[ti.State]} 85 | if ti.Options&sysTCPI_OPT_WSCALE != 0 { 86 | i.Options = append(i.Options, WindowScale(ti.Pad_cgo_0[0]>>4)) 87 | i.PeerOptions = append(i.PeerOptions, WindowScale(ti.Pad_cgo_0[0]&0x0f)) 88 | } 89 | if ti.Options&sysTCPI_OPT_SACK != 0 { 90 | i.Options = append(i.Options, SACKPermitted(true)) 91 | i.PeerOptions = append(i.PeerOptions, SACKPermitted(true)) 92 | } 93 | if ti.Options&sysTCPI_OPT_TIMESTAMPS != 0 { 94 | i.Options = append(i.Options, Timestamps(true)) 95 | i.PeerOptions = append(i.PeerOptions, Timestamps(true)) 96 | } 97 | i.SenderMSS = MaxSegSize(ti.Snd_mss) 98 | i.ReceiverMSS = MaxSegSize(ti.Rcv_mss) 99 | i.RTT = time.Duration(ti.Rtt) * time.Microsecond 100 | i.RTTVar = time.Duration(ti.Rttvar) * time.Microsecond 101 | i.RTO = time.Duration(ti.Rto) * time.Microsecond 102 | i.ATO = time.Duration(ti.Ato) * time.Microsecond 103 | i.LastDataSent = time.Duration(ti.Last_data_sent) * time.Millisecond 104 | i.LastDataReceived = time.Duration(ti.Last_data_recv) * time.Millisecond 105 | i.LastAckReceived = time.Duration(ti.Last_ack_recv) * time.Millisecond 106 | i.FlowControl = &FlowControl{ 107 | ReceiverWindow: uint(ti.Rcv_space), 108 | } 109 | i.CongestionControl = &CongestionControl{ 110 | SenderSSThreshold: uint(ti.Snd_ssthresh), 111 | ReceiverSSThreshold: uint(ti.Rcv_ssthresh), 112 | SenderWindowSegs: uint(ti.Snd_cwnd), 113 | } 114 | i.Sys = &SysInfo{ 115 | PathMTU: uint(ti.Pmtu), 116 | AdvertisedMSS: MaxSegSize(ti.Advmss), 117 | CAState: CAState(ti.Ca_state), 118 | Retransmissions: uint(ti.Retransmits), 119 | Backoffs: uint(ti.Backoff), 120 | WindowOrKeepAliveProbes: uint(ti.Probes), 121 | UnackedSegs: uint(ti.Unacked), 122 | SackedSegs: uint(ti.Sacked), 123 | LostSegs: uint(ti.Lost), 124 | RetransSegs: uint(ti.Retrans), 125 | ForwardAckSegs: uint(ti.Fackets), 126 | ReorderedSegs: uint(ti.Reordering), 127 | ReceiverRTT: time.Duration(ti.Rcv_rtt) * time.Microsecond, 128 | TotalRetransSegs: uint(ti.Total_retrans), 129 | PacingRate: uint64(ti.Pacing_rate), 130 | ThruBytesAcked: uint64(ti.Bytes_acked), 131 | ThruBytesReceived: uint64(ti.Bytes_received), 132 | SegsIn: uint(ti.Segs_in), 133 | SegsOut: uint(ti.Segs_out), 134 | NotSentBytes: uint(ti.Notsent_bytes), 135 | MinRTT: time.Duration(ti.Min_rtt) * time.Microsecond, 136 | DataSegsIn: uint(ti.Data_segs_in), 137 | DataSegsOut: uint(ti.Data_segs_out), 138 | } 139 | return i, nil 140 | } 141 | 142 | func parseInfo3_19(b []byte) (tcpopt.Option, error) { 143 | if len(b) < sizeofTCPInfoV3_19 { 144 | return parseInfo2_6_10(b) 145 | } 146 | ti := (*tcpInfo3_19)(unsafe.Pointer(&b[0])) 147 | i := &Info{State: sysStates[ti.State]} 148 | if ti.Options&sysTCPI_OPT_WSCALE != 0 { 149 | i.Options = append(i.Options, WindowScale(ti.Pad_cgo_0[0]>>4)) 150 | i.PeerOptions = append(i.PeerOptions, WindowScale(ti.Pad_cgo_0[0]&0x0f)) 151 | } 152 | if ti.Options&sysTCPI_OPT_SACK != 0 { 153 | i.Options = append(i.Options, SACKPermitted(true)) 154 | i.PeerOptions = append(i.PeerOptions, SACKPermitted(true)) 155 | } 156 | if ti.Options&sysTCPI_OPT_TIMESTAMPS != 0 { 157 | i.Options = append(i.Options, Timestamps(true)) 158 | i.PeerOptions = append(i.PeerOptions, Timestamps(true)) 159 | } 160 | i.SenderMSS = MaxSegSize(ti.Snd_mss) 161 | i.ReceiverMSS = MaxSegSize(ti.Rcv_mss) 162 | i.RTT = time.Duration(ti.Rtt) * time.Microsecond 163 | i.RTTVar = time.Duration(ti.Rttvar) * time.Microsecond 164 | i.RTO = time.Duration(ti.Rto) * time.Microsecond 165 | i.ATO = time.Duration(ti.Ato) * time.Microsecond 166 | i.LastDataSent = time.Duration(ti.Last_data_sent) * time.Millisecond 167 | i.LastDataReceived = time.Duration(ti.Last_data_recv) * time.Millisecond 168 | i.LastAckReceived = time.Duration(ti.Last_ack_recv) * time.Millisecond 169 | i.FlowControl = &FlowControl{ 170 | ReceiverWindow: uint(ti.Rcv_space), 171 | } 172 | i.CongestionControl = &CongestionControl{ 173 | SenderSSThreshold: uint(ti.Snd_ssthresh), 174 | ReceiverSSThreshold: uint(ti.Rcv_ssthresh), 175 | SenderWindowSegs: uint(ti.Snd_cwnd), 176 | } 177 | i.Sys = &SysInfo{ 178 | PathMTU: uint(ti.Pmtu), 179 | AdvertisedMSS: MaxSegSize(ti.Advmss), 180 | CAState: CAState(ti.Ca_state), 181 | Retransmissions: uint(ti.Retransmits), 182 | Backoffs: uint(ti.Backoff), 183 | WindowOrKeepAliveProbes: uint(ti.Probes), 184 | UnackedSegs: uint(ti.Unacked), 185 | SackedSegs: uint(ti.Sacked), 186 | LostSegs: uint(ti.Lost), 187 | RetransSegs: uint(ti.Retrans), 188 | ForwardAckSegs: uint(ti.Fackets), 189 | ReorderedSegs: uint(ti.Reordering), 190 | ReceiverRTT: time.Duration(ti.Rcv_rtt) * time.Microsecond, 191 | TotalRetransSegs: uint(ti.Total_retrans), 192 | PacingRate: uint64(ti.Pacing_rate), 193 | } 194 | return i, nil 195 | } 196 | 197 | func parseInfo2_6_10(b []byte) (tcpopt.Option, error) { 198 | if len(b) < sizeofTCPInfoV2_6_10 { 199 | return nil, errors.New("short buffer") 200 | } 201 | ti := (*tcpInfo2_6_10)(unsafe.Pointer(&b[0])) 202 | i := &Info{State: sysStates[ti.State]} 203 | if ti.Options&sysTCPI_OPT_WSCALE != 0 { 204 | i.Options = append(i.Options, WindowScale(ti.Pad_cgo_0[0]>>4)) 205 | i.PeerOptions = append(i.PeerOptions, WindowScale(ti.Pad_cgo_0[0]&0x0f)) 206 | } 207 | if ti.Options&sysTCPI_OPT_SACK != 0 { 208 | i.Options = append(i.Options, SACKPermitted(true)) 209 | i.PeerOptions = append(i.PeerOptions, SACKPermitted(true)) 210 | } 211 | if ti.Options&sysTCPI_OPT_TIMESTAMPS != 0 { 212 | i.Options = append(i.Options, Timestamps(true)) 213 | i.PeerOptions = append(i.PeerOptions, Timestamps(true)) 214 | } 215 | i.SenderMSS = MaxSegSize(ti.Snd_mss) 216 | i.ReceiverMSS = MaxSegSize(ti.Rcv_mss) 217 | i.RTT = time.Duration(ti.Rtt) * time.Microsecond 218 | i.RTTVar = time.Duration(ti.Rttvar) * time.Microsecond 219 | i.RTO = time.Duration(ti.Rto) * time.Microsecond 220 | i.ATO = time.Duration(ti.Ato) * time.Microsecond 221 | i.LastDataSent = time.Duration(ti.Last_data_sent) * time.Millisecond 222 | i.LastDataReceived = time.Duration(ti.Last_data_recv) * time.Millisecond 223 | i.LastAckReceived = time.Duration(ti.Last_ack_recv) * time.Millisecond 224 | i.FlowControl = &FlowControl{ 225 | ReceiverWindow: uint(ti.Rcv_space), 226 | } 227 | i.CongestionControl = &CongestionControl{ 228 | SenderSSThreshold: uint(ti.Snd_ssthresh), 229 | ReceiverSSThreshold: uint(ti.Rcv_ssthresh), 230 | SenderWindowSegs: uint(ti.Snd_cwnd), 231 | } 232 | i.Sys = &SysInfo{ 233 | PathMTU: uint(ti.Pmtu), 234 | AdvertisedMSS: MaxSegSize(ti.Advmss), 235 | CAState: CAState(ti.Ca_state), 236 | Retransmissions: uint(ti.Retransmits), 237 | Backoffs: uint(ti.Backoff), 238 | WindowOrKeepAliveProbes: uint(ti.Probes), 239 | UnackedSegs: uint(ti.Unacked), 240 | SackedSegs: uint(ti.Sacked), 241 | LostSegs: uint(ti.Lost), 242 | RetransSegs: uint(ti.Retrans), 243 | ForwardAckSegs: uint(ti.Fackets), 244 | ReorderedSegs: uint(ti.Reordering), 245 | ReceiverRTT: time.Duration(ti.Rcv_rtt) * time.Microsecond, 246 | TotalRetransSegs: uint(ti.Total_retrans), 247 | } 248 | return i, nil 249 | } 250 | 251 | // A VegasInfo represents Vegas congestion control information. 252 | type VegasInfo struct { 253 | Enabled bool `json:"enabled"` 254 | RoundTrips uint `json:"rnd_trips"` // # of round-trips 255 | RTT time.Duration `json:"rtt"` // round-trip time 256 | MinRTT time.Duration `json:"min_rtt"` // minimum round-trip time 257 | } 258 | 259 | // Algorithm implements the Algorithm method of CCAlgorithmInfo 260 | // interface. 261 | func (vi *VegasInfo) Algorithm() string { return "vegas" } 262 | 263 | // A CEState represents a state of ECN congestion encountered (CE) 264 | // codepoint. 265 | type CEState int 266 | 267 | // A DCTCPInfo represents Datacenter TCP congestion control 268 | // information. 269 | type DCTCPInfo struct { 270 | Enabled bool `json:"enabled"` 271 | CEState CEState `json:"ce_state"` // state of ECN CE codepoint 272 | Alpha uint `json:"alpha"` // fraction of bytes sent 273 | ECNAckedBytes uint `json:"ecn_acked"` // # of acked bytes with ECN 274 | TotalAckedBytes uint `json:"total_acked"` // total # of acked bytes 275 | } 276 | 277 | // Algorithm implements the Algorithm method of CCAlgorithmInfo 278 | // interface. 279 | func (di *DCTCPInfo) Algorithm() string { return "dctcp" } 280 | 281 | // A BBRInfo represents Bottleneck Bandwidth and Round-trip 282 | // propagation time-based congestion control information. 283 | type BBRInfo struct { 284 | MaxBW uint64 `json:"max_bw"` // maximum-filtered bandwidth in bps 285 | MinRTT time.Duration `json:"min_rtt"` // minimum-filtered round-trip time 286 | PacingGain uint `json:"pacing_gain"` // pacing gain shifted left 8 bits 287 | CongWindowGain uint `json:"cwnd_gain"` // congestion window gain shifted left 8 bits 288 | } 289 | 290 | // Algorithm implements the Algorithm method of CCAlgorithmInfo 291 | // interface. 292 | func (bi *BBRInfo) Algorithm() string { return "bbr" } 293 | 294 | func parseCCAlgorithmInfo(name string, b []byte) (CCAlgorithmInfo, error) { 295 | if strings.HasPrefix(name, "dctcp") { 296 | if len(b) < sizeofTCPDCTCPInfo { 297 | return nil, errors.New("short buffer") 298 | } 299 | sdi := (*tcpDCTCPInfo)(unsafe.Pointer(&b[0])) 300 | di := &DCTCPInfo{Alpha: uint(sdi.Alpha)} 301 | if sdi.Enabled != 0 { 302 | di.Enabled = true 303 | } 304 | return di, nil 305 | } 306 | if strings.HasPrefix(name, "bbr") { 307 | if len(b) < sizeofTCPBBRInfo { 308 | return nil, errors.New("short buffer") 309 | } 310 | sbi := (*tcpBBRInfo)(unsafe.Pointer(&b[0])) 311 | return &BBRInfo{ 312 | MaxBW: uint64(sbi.Bw_hi)<<32 | uint64(sbi.Bw_lo), 313 | MinRTT: time.Duration(sbi.Min_rtt) * time.Microsecond, 314 | PacingGain: uint(sbi.Pacing_gain), 315 | CongWindowGain: uint(sbi.Cwnd_gain), 316 | }, nil 317 | } 318 | if len(b) < sizeofTCPVegasInfo { 319 | return nil, errors.New("short buffer") 320 | } 321 | svi := (*tcpVegasInfo)(unsafe.Pointer(&b[0])) 322 | vi := &VegasInfo{ 323 | RoundTrips: uint(svi.Rttcnt), 324 | RTT: time.Duration(svi.Rtt) * time.Microsecond, 325 | MinRTT: time.Duration(svi.Minrtt) * time.Microsecond, 326 | } 327 | if svi.Enabled != 0 { 328 | vi.Enabled = true 329 | } 330 | return vi, nil 331 | } 332 | --------------------------------------------------------------------------------