From 855ec85dbc40c226db0b4888e5a004929e9f6ffa Mon Sep 17 00:00:00 2001 From: WAKAYAMA Shirou Date: Fri, 16 May 2014 11:33:35 +0900 Subject: [PATCH 1/4] implement net_io_counters on Windows. --- common.go | 24 +++++++++++++++++++ common_windows.go | 11 +++++++++ net_windows.go | 60 +++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 93 insertions(+), 2 deletions(-) diff --git a/common.go b/common.go index 9130303..4f05543 100644 --- a/common.go +++ b/common.go @@ -9,6 +9,7 @@ package gopsutil import ( "bufio" "os" + "reflect" "strconv" "strings" ) @@ -77,3 +78,26 @@ func stringContains(target []string, src string) bool { } return false } + +// get struct attributes. +// This method is used only for debugging platform dependent code. +func attributes(m interface{}) map[string]reflect.Type { + typ := reflect.TypeOf(m) + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + } + + attrs := make(map[string]reflect.Type) + if typ.Kind() != reflect.Struct { + return nil + } + + for i := 0; i < typ.NumField(); i++ { + p := typ.Field(i) + if !p.Anonymous { + attrs[p.Name] = p.Type + } + } + + return attrs +} diff --git a/common_windows.go b/common_windows.go index 04fea1d..e84abc3 100644 --- a/common_windows.go +++ b/common_windows.go @@ -4,6 +4,7 @@ package gopsutil import ( "syscall" + "unsafe" ) var ( @@ -18,3 +19,13 @@ type FILETIME struct { DwLowDateTime uint32 DwHighDateTime uint32 } + +// borrowed from net/interface_windows.go +func bytePtrToString(p *uint8) string { + a := (*[10000]uint8)(unsafe.Pointer(p)) + i := 0 + for a[i] != 0 { + i++ + } + return string(a[:i]) +} diff --git a/net_windows.go b/net_windows.go index 329b544..c32f956 100644 --- a/net_windows.go +++ b/net_windows.go @@ -3,9 +3,65 @@ package gopsutil import ( - "errors" + "net" + "os" + "syscall" + "unsafe" ) func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) { - return nil, errors.New("not implemented yet") + ifs, err := net.Interfaces() + if err != nil { + return nil, err + } + + ai, err := getAdapterList() + if err != nil { + return nil, err + } + var ret []NetIOCountersStat + + for _, ifi := range ifs { + name := ifi.Name + for ; ai != nil; ai = ai.Next { + name = bytePtrToString(&ai.Description[0]) + c := NetIOCountersStat{ + Name: name, + } + + row := syscall.MibIfRow{Index: ai.Index} + e := syscall.GetIfEntry(&row) + if e != nil { + return nil, os.NewSyscallError("GetIfEntry", e) + } + c.BytesSent = uint64(row.OutOctets) + c.BytesRecv = uint64(row.InOctets) + c.PacketsSent = uint64(row.OutUcastPkts) + c.PacketsRecv = uint64(row.InUcastPkts) + c.Errin = uint64(row.InErrors) + c.Errout = uint64(row.OutErrors) + c.Dropin = uint64(row.InDiscards) + c.Dropout = uint64(row.OutDiscards) + + ret = append(ret, c) + } + } + return ret, nil +} + +// borrowed from src/pkg/net/interface_windows.go +func getAdapterList() (*syscall.IpAdapterInfo, error) { + b := make([]byte, 1000) + l := uint32(len(b)) + a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0])) + err := syscall.GetAdaptersInfo(a, &l) + if err == syscall.ERROR_BUFFER_OVERFLOW { + b = make([]byte, l) + a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0])) + err = syscall.GetAdaptersInfo(a, &l) + } + if err != nil { + return nil, os.NewSyscallError("GetAdaptersInfo", err) + } + return a, nil } From 49857dbdd04e8970e0388d892d99c3bce2901fcf Mon Sep 17 00:00:00 2001 From: WAKAYAMA Shirou Date: Fri, 16 May 2014 12:21:17 +0900 Subject: [PATCH 2/4] add NetConnection placeholder on windows. --- net_windows.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/net_windows.go b/net_windows.go index c32f956..74ce1b3 100644 --- a/net_windows.go +++ b/net_windows.go @@ -3,12 +3,31 @@ package gopsutil import ( + "errors" "net" "os" "syscall" "unsafe" ) +var ( + modiphlpapi = NewLazyDLL("iphlpapi.dll") + procGetExtendedTcpTable = modiphlpapi.NewProc("GetExtendedTcpTable") + procGetExtendedUdpTable = modiphlpapi.NewProc("GetExtendedUdpTable") +) + +const ( + TCP_TABLE_BASIC_LISTENER = iota + TCP_TABLE_BASIC_CONNECTIONS + TCP_TABLE_BASIC_ALL + TCP_TABLE_OWNER_PID_LISTENER + TCP_TABLE_OWNER_PID_CONNECTIONS + TCP_TABLE_OWNER_PID_ALL + TCP_TABLE_OWNER_MODULE_LISTENER + TCP_TABLE_OWNER_MODULE_CONNECTIONS + TCP_TABLE_OWNER_MODULE_ALL +) + func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) { ifs, err := net.Interfaces() if err != nil { @@ -49,6 +68,13 @@ func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) { return ret, nil } +// Return a list of network connections opened by a process +func NetConnections(kind string) ([]NetConnectionStat, error) { + var ret []NetConnectionStat + + return ret, erros.New("not implemented yet") +} + // borrowed from src/pkg/net/interface_windows.go func getAdapterList() (*syscall.IpAdapterInfo, error) { b := make([]byte, 1000) From 049edefab0c21b003ed883facaed39dafd67316d Mon Sep 17 00:00:00 2001 From: WAKAYAMA Shirou Date: Fri, 16 May 2014 12:21:55 +0900 Subject: [PATCH 3/4] rename json tag to more understandable on NetConnectionsStat --- net.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net.go b/net.go index 065159d..a406c3d 100644 --- a/net.go +++ b/net.go @@ -25,8 +25,8 @@ type NetConnectionStat struct { Fd uint32 `json:"fd"` Family uint32 `json:"family"` Type uint32 `json:"type"` - Laddr Addr `json:"laddr"` - Raddr Addr `json:"raddr"` + Laddr Addr `json:"localaddr"` + Raddr Addr `json:"remoteaddr"` Status string `json:"status"` Pid int32 `json:"pid"` } From 4cb5a9a806aef174896902ce3aad2d95d4cc90e1 Mon Sep 17 00:00:00 2001 From: Shirou WAKAYAMA Date: Fri, 16 May 2014 14:21:19 +0900 Subject: [PATCH 4/4] fix change of json tag name. --- net_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net_test.go b/net_test.go index 496f7d7..6d7fde2 100644 --- a/net_test.go +++ b/net_test.go @@ -31,7 +31,7 @@ func TestNetConnectionStatString(t *testing.T) { Family: 10, Type: 10, } - e := `{"fd":10,"family":10,"type":10,"laddr":{"ip":"","port":0},"raddr":{"ip":"","port":0},"status":"","pid":0}` + e := `{"fd":10,"family":10,"type":10,"localaddr":{"ip":"","port":0},"remoteaddr":{"ip":"","port":0},"status":"","pid":0}` if e != fmt.Sprintf("%v", v) { t.Errorf("NetConnectionStat string is invalid: %v", v) }