diff --git a/src/admin/getpeers.go b/src/admin/getpeers.go index 9ccf9e2f..ecb28726 100644 --- a/src/admin/getpeers.go +++ b/src/admin/getpeers.go @@ -19,6 +19,9 @@ type PeerEntry struct { Port uint64 `json:"port"` Coords []uint64 `json:"coords"` Remote string `json:"remote"` + RXBytes uint64 `json:"bytes_recvd"` + TXBytes uint64 `json:"bytes_sent"` + Uptime float64 `json:"uptime"` } func (a *AdminSocket) getPeersHandler(req *GetPeersRequest, res *GetPeersResponse) error { @@ -31,6 +34,9 @@ func (a *AdminSocket) getPeersHandler(req *GetPeersRequest, res *GetPeersRespons Port: p.Port, Coords: p.Coords, Remote: p.Remote, + RXBytes: p.RXBytes, + TXBytes: p.TXBytes, + Uptime: p.Uptime.Seconds(), } } return nil diff --git a/src/core/api.go b/src/core/api.go index ae13d499..fabd7439 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -2,12 +2,16 @@ package core import ( "crypto/ed25519" + "sync/atomic" + "time" + //"encoding/hex" "encoding/json" //"errors" //"fmt" "net" "net/url" + //"sort" //"time" @@ -24,11 +28,14 @@ type Self struct { } type Peer struct { - Key ed25519.PublicKey - Root ed25519.PublicKey - Coords []uint64 - Port uint64 - Remote string + Key ed25519.PublicKey + Root ed25519.PublicKey + Coords []uint64 + Port uint64 + Remote string + RXBytes uint64 + TXBytes uint64 + Uptime time.Duration } type DHTEntry struct { @@ -74,6 +81,11 @@ func (c *Core) GetPeers() []Peer { if name := names[p.Conn]; name != "" { info.Remote = name } + if linkconn, ok := p.Conn.(*linkConn); ok { + info.RXBytes = atomic.LoadUint64(&linkconn.rx) + info.TXBytes = atomic.LoadUint64(&linkconn.tx) + info.Uptime = time.Since(linkconn.up) + } peers = append(peers, info) } return peers diff --git a/src/core/link.go b/src/core/link.go index dfc8a2fe..f96c9be9 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -14,6 +14,8 @@ import ( //"sync/atomic" "time" + "sync/atomic" + "github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/util" "golang.org/x/net/proxy" @@ -40,7 +42,7 @@ type linkInfo struct { type link struct { lname string links *links - conn net.Conn + conn *linkConn options linkOptions info linkInfo incoming bool @@ -124,7 +126,10 @@ func (l *links) call(u *url.URL, sintf string) error { func (l *links) create(conn net.Conn, name, linkType, local, remote string, incoming, force bool, options linkOptions) (*link, error) { // Technically anything unique would work for names, but let's pick something human readable, just for debugging intf := link{ - conn: conn, + conn: &linkConn{ + Conn: conn, + up: time.Now(), + }, lname: name, links: l, options: options, @@ -272,3 +277,24 @@ func (intf *link) close() { func (intf *link) name() string { return intf.lname } + +type linkConn struct { + // tx and rx are at the beginning of the struct to ensure 64-bit alignment + // on 32-bit platforms, see https://pkg.go.dev/sync/atomic#pkg-note-BUG + rx uint64 + tx uint64 + up time.Time + net.Conn +} + +func (c *linkConn) Read(p []byte) (n int, err error) { + n, err = c.Conn.Read(p) + atomic.AddUint64(&c.rx, uint64(n)) + return +} + +func (c *linkConn) Write(p []byte) (n int, err error) { + n, err = c.Conn.Write(p) + atomic.AddUint64(&c.tx, uint64(n)) + return +}