diff --git a/common.go b/common.go index 9a15d5e..e0395c8 100644 --- a/common.go +++ b/common.go @@ -9,6 +9,7 @@ package gopsutil import ( "bufio" "os" + "reflect" "strconv" "strings" ) @@ -85,3 +86,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.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"` } 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) } diff --git a/net_windows.go b/net_windows.go index 329b544..74ce1b3 100644 --- a/net_windows.go +++ b/net_windows.go @@ -4,8 +4,90 @@ 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) { - 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 +} + +// 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) + 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 }