From 6c352016d8a5b8b9a774f49c9325e7fd268fe3f6 Mon Sep 17 00:00:00 2001 From: Shirou WAKAYAMA Date: Tue, 1 Mar 2016 23:38:13 +0900 Subject: [PATCH 1/7] [net]linux: start replacing lsof. still work in progress. --- internal/common/common.go | 10 ++ net/net_linux.go | 294 ++++++++++++++++++++++++++++++++++++++ net/net_linux_test.go | 71 +++++++++ net/net_unix.go | 2 +- 4 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 net/net_linux_test.go diff --git a/internal/common/common.go b/internal/common/common.go index 8c38bdb26..53e0667a2 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -206,6 +206,16 @@ func StringsContains(target []string, src string) bool { return false } +// IntContains checks the src in any int of the target int slice. +func IntContains(target []int, src int) bool { + for _, t := range target { + if src == t { + return true + } + } + return false +} + // get struct attributes. // This method is used only for debugging platform dependent code. func attributes(m interface{}) map[string]reflect.Type { diff --git a/net/net_linux.go b/net/net_linux.go index e2e217dc1..097da457e 100644 --- a/net/net_linux.go +++ b/net/net_linux.go @@ -3,9 +3,15 @@ package net import ( + "encoding/hex" "errors" + "fmt" + "io/ioutil" + "net" + "os" "strconv" "strings" + "syscall" "github.com/shirou/gopsutil/internal/common" ) @@ -192,3 +198,291 @@ func NetFilterCounters() ([]NetFilterStat, error) { stats = append(stats, payload) return stats, nil } + +type netConnectionKindType struct { + family int + sockType int +} + +var KindTCP4 = netConnectionKindType{ + family: syscall.AF_INET, + sockType: syscall.SOCK_STREAM, +} +var KindTCP6 = netConnectionKindType{ + family: syscall.AF_INET6, + sockType: syscall.SOCK_STREAM, +} +var KindUDP4 = netConnectionKindType{ + family: syscall.AF_INET, + sockType: syscall.SOCK_DGRAM, +} +var KindUDP6 = netConnectionKindType{ + family: syscall.AF_INET6, + sockType: syscall.SOCK_DGRAM, +} +var KindUNIX = netConnectionKindType{ + family: syscall.AF_UNIX, +} + +var netConnectionKindMap = map[string][]netConnectionKindType{ + "all": []netConnectionKindType{KindTCP4, KindTCP6, KindUDP4, KindUDP6, KindUNIX}, + "tcp": []netConnectionKindType{KindTCP4, KindTCP6}, + "tcp4": []netConnectionKindType{KindTCP4}, + "tcp6": []netConnectionKindType{KindTCP6}, + "udp": []netConnectionKindType{KindUDP4, KindUDP6}, + "udp4": []netConnectionKindType{KindUDP4}, + "udp6": []netConnectionKindType{KindUDP6}, + "unix": []netConnectionKindType{KindUNIX}, + "inet": []netConnectionKindType{KindTCP4, KindTCP6, KindUDP4, KindUDP6}, + "inet4": []netConnectionKindType{KindTCP4, KindUDP4}, + "inet6": []netConnectionKindType{KindTCP6, KindUDP6}, +} + +type inodeMap struct { + pid int32 + fd string +} + +type bb struct { + fd int + family int + sockType int + laddr string + raddr string + status string + bound_pid int32 +} + +// Return a list of network connections opened. +func NetConnections(kind string) ([]NetConnectionStat, error) { + return NetConnectionsPid(kind, 0) +} + +// Return a list of network connections opened by a process. +func NetConnectionsPid(kind string, pid int32) ([]NetConnectionStat, error) { + tmap, ok := netConnectionKindMap[kind] + if !ok { + return nil, fmt.Errorf("invalid kind, %s", kind) + } + root := common.HostProc() + var err error + var inodes map[string][]inodeMap + if pid == 0 { + inodes, err = getProcInodesAll(root) + } else { + inodes, err = getProcInodes(root, pid) + } + if err != nil { + return nil, fmt.Errorf("cound not get pid(s), %d", pid) + } + + for _, t := range tmap { + fmt.Println(t) + fmt.Println(inodes) + + var path string + var ls []string + switch t.family { + case syscall.AF_INET: + path = fmt.Sprintf("%d/net/%s", pid, "tcp") + ls, err = processInet(path, t, inodes, pid) + case syscall.AF_INET6: + path = fmt.Sprintf("%d/net/%s", pid, "tcp6") + ls, err = processInet(path, t, inodes, pid) + case syscall.AF_UNIX: + path = fmt.Sprintf("%d/net/%s", pid, "unix") + ls, err = processInet(path, t, inodes, pid) + } + if err != nil { + return nil, err + } + for _, sss := range ls { + fmt.Println(sss) + } + + } + + return []NetConnectionStat{}, nil +} + +// getProcInodes returnes fd of the pid. +func getProcInodes(root string, pid int32) (map[string][]inodeMap, error) { + ret := make(map[string][]inodeMap) + + dir := fmt.Sprintf("%s/%d/fd", root, pid) + + files, err := ioutil.ReadDir(dir) + if err != nil { + return ret, nil + } + for _, fd := range files { + inodePath := fmt.Sprintf("%s/%d/fd/%s", root, pid, fd.Name()) + + inode, err := os.Readlink(inodePath) + if err != nil { + continue + } + + fmt.Println(inodePath) + if strings.HasPrefix(inode, "socket:[") { + // the process is using a socket + l := len(inode) + inode = inode[8 : l-1] + } + + _, ok := ret[inode] + if !ok { + ret[inode] = make([]inodeMap, 0) + } + + i := inodeMap{ + pid: pid, + fd: fd.Name(), + } + ret[inode] = append(ret[inode], i) + } + + return ret, nil +} + +// Pids retunres all pids. +// Note: this is a copy of process_linux.Pids() +// FIXME: Import process occures import cycle. +// move to common made other platform breaking. Need consider. +func Pids() ([]int32, error) { + var ret []int32 + + d, err := os.Open(common.HostProc()) + if err != nil { + return nil, err + } + defer d.Close() + + fnames, err := d.Readdirnames(-1) + if err != nil { + return nil, err + } + for _, fname := range fnames { + pid, err := strconv.ParseInt(fname, 10, 32) + if err != nil { + // if not numeric name, just skip + continue + } + ret = append(ret, int32(pid)) + } + + return ret, nil +} + +func getProcInodesAll(root string) (map[string][]inodeMap, error) { + pids, err := Pids() + if err != nil { + return nil, err + } + ret := make(map[string][]inodeMap) + + for _, pid := range pids { + t, err := getProcInodes(root, pid) + if err != nil { + return ret, err + } + if len(t) == 0 { + continue + } + // TODO: update ret. + + fmt.Println(t) + } + + return ret, nil +} + +// decodeAddress decode addresse represents addr in proc/net/* +// ex: +// "0500000A:0016" -> "10.0.0.5", 22 +// "0085002452100113070057A13F025401:0035" -> "2400:8500:1301:1052:a157:7:154:23f", 53 +func decodeAddress(family int, src string) (net.IP, int, error) { + t := strings.Split(src, ":") + if len(t) != 2 { + return nil, 0, fmt.Errorf("does not contain port, %s", src) + } + addr := t[0] + port, err := strconv.ParseInt("0x"+t[1], 0, 64) + if err != nil { + return nil, 0, fmt.Errorf("invalid port, %s", src) + } + decoded, err := hex.DecodeString(addr) + if err != nil { + return nil, 0, fmt.Errorf("decode error:", err) + } + var ip net.IP + // Assumes this is little_endian + if family == syscall.AF_INET { + ip = net.IP(Reverse(decoded)) + } else { // IPv6 + ip, err = parseIPv6HexString(decoded) + if err != nil { + return nil, 0, err + } + } + return ip, int(port), nil +} + +// Reverse reverses array of bytes. +func Reverse(s []byte) []byte { + for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { + s[i], s[j] = s[j], s[i] + } + return s +} + +// parseIPv6HexString parse array of bytes to IPv6 string +func parseIPv6HexString(src []byte) (net.IP, error) { + if len(src) != 16 { + return nil, fmt.Errorf("invalid IPv6 string") + } + + buf := make([]byte, 0, 16) + for i := 0; i < len(src); i += 4 { + r := Reverse(src[i : i+4]) + buf = append(buf, r...) + } + return net.IP(buf), nil +} + +func processInet(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]string, error) { + + if strings.HasSuffix(file, "6") && !common.PathExists(file) { + // IPv6 not supported, return empty. + return []string{}, nil + } + lines, err := common.ReadLines(file) + if err != nil { + return nil, err + } + // skip first line + for _, line := range lines[1:] { + l := strings.Fields(line) + if len(l) < 10 { + continue + } + laddr := l[1] + raddr := l[2] + status := l[3] + inode, err := strconv.Atoi(l[9]) + if err != nil { + continue + } + fmt.Println(laddr) + fmt.Println(raddr) + fmt.Println(status) + fmt.Println(inode) + } + + return nil, nil +} + +func processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]string, error) { + + return nil, nil +} diff --git a/net/net_linux_test.go b/net/net_linux_test.go new file mode 100644 index 000000000..debe16685 --- /dev/null +++ b/net/net_linux_test.go @@ -0,0 +1,71 @@ +package net + +import ( + "fmt" + "syscall" + "testing" + + "github.com/shirou/gopsutil/internal/common" + "github.com/stretchr/testify/assert" +) + +func TestGetProcInodes(t *testing.T) { + root := common.HostProc("") + + // /proc/19957/fd + + v, err := getProcInodes(root, 19957) + if err != nil { + t.Fatal(err) + } + fmt.Println(v) +} + +type AddrTest struct { + IP string + Port int + Error bool +} + +func TestDecodeAddress(t *testing.T) { + assert := assert.New(t) + + addr := map[string]AddrTest{ + "0500000A:0016": AddrTest{ + IP: "10.0.0.5", + Port: 22, + }, + "0100007F:D1C2": AddrTest{ + IP: "127.0.0.1", + Port: 53698, + }, + "11111:0035": AddrTest{ + Error: true, + }, + "0100007F:BLAH": AddrTest{ + Error: true, + }, + "0085002452100113070057A13F025401:0035": AddrTest{ + IP: "2400:8500:1301:1052:a157:7:154:23f", + Port: 53, + }, + "00855210011307F025401:0035": AddrTest{ + Error: true, + }, + } + + for src, dst := range addr { + family := syscall.AF_INET + if len(src) > 13 { + family = syscall.AF_INET6 + } + ip, port, err := decodeAddress(family, src) + if dst.Error { + assert.NotNil(err, src) + } else { + assert.Nil(err, src) + assert.Equal(dst.IP, ip.String(), src) + assert.Equal(dst.Port, port, src) + } + } +} diff --git a/net/net_unix.go b/net/net_unix.go index fe2f1eb4d..c267c25b5 100644 --- a/net/net_unix.go +++ b/net/net_unix.go @@ -1,4 +1,4 @@ -// +build linux freebsd darwin +// +build freebsd darwin package net From 32c62b5d484e1ffc94aa97ed4de2642d9ace5872 Mon Sep 17 00:00:00 2001 From: Shirou WAKAYAMA Date: Fri, 4 Mar 2016 23:42:22 +0900 Subject: [PATCH 2/7] [net]linux: implement processInet(). --- net/net_linux.go | 196 +++++++++++++++++++++++++++++------------- net/net_linux_test.go | 19 ++-- 2 files changed, 142 insertions(+), 73 deletions(-) diff --git a/net/net_linux.go b/net/net_linux.go index 097da457e..d206f01b0 100644 --- a/net/net_linux.go +++ b/net/net_linux.go @@ -199,58 +199,80 @@ func NetFilterCounters() ([]NetFilterStat, error) { return stats, nil } +// http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h +var TCPStatuses = map[string]string{ + "01": "ESTABLISHED", + "02": "SYN_SENT", + "03": "SYN_RECV", + "04": "FIN_WAIT1", + "05": "FIN_WAIT2", + "06": "TIME_WAIT", + "07": "CLOSE", + "08": "CLOSE_WAIT", + "09": "LAST_ACK", + "0A": "LISTEN", + "0B": "CLOSING", +} + type netConnectionKindType struct { - family int - sockType int + family uint32 + sockType uint32 + f string // file name } -var KindTCP4 = netConnectionKindType{ +var kindTCP4 = netConnectionKindType{ family: syscall.AF_INET, sockType: syscall.SOCK_STREAM, + f: "tcp", } -var KindTCP6 = netConnectionKindType{ +var kindTCP6 = netConnectionKindType{ family: syscall.AF_INET6, sockType: syscall.SOCK_STREAM, + f: "tcp6", } -var KindUDP4 = netConnectionKindType{ +var kindUDP4 = netConnectionKindType{ family: syscall.AF_INET, sockType: syscall.SOCK_DGRAM, + f: "udp", } -var KindUDP6 = netConnectionKindType{ +var kindUDP6 = netConnectionKindType{ family: syscall.AF_INET6, sockType: syscall.SOCK_DGRAM, + f: "udp6", } -var KindUNIX = netConnectionKindType{ +var kindUNIX = netConnectionKindType{ family: syscall.AF_UNIX, + f: "unix", } var netConnectionKindMap = map[string][]netConnectionKindType{ - "all": []netConnectionKindType{KindTCP4, KindTCP6, KindUDP4, KindUDP6, KindUNIX}, - "tcp": []netConnectionKindType{KindTCP4, KindTCP6}, - "tcp4": []netConnectionKindType{KindTCP4}, - "tcp6": []netConnectionKindType{KindTCP6}, - "udp": []netConnectionKindType{KindUDP4, KindUDP6}, - "udp4": []netConnectionKindType{KindUDP4}, - "udp6": []netConnectionKindType{KindUDP6}, - "unix": []netConnectionKindType{KindUNIX}, - "inet": []netConnectionKindType{KindTCP4, KindTCP6, KindUDP4, KindUDP6}, - "inet4": []netConnectionKindType{KindTCP4, KindUDP4}, - "inet6": []netConnectionKindType{KindTCP6, KindUDP6}, + "all": []netConnectionKindType{kindTCP4, kindTCP6, kindUDP4, kindUDP6, kindUNIX}, + "tcp": []netConnectionKindType{kindTCP4, kindTCP6}, + "tcp4": []netConnectionKindType{kindTCP4}, + "tcp6": []netConnectionKindType{kindTCP6}, + "udp": []netConnectionKindType{kindUDP4, kindUDP6}, + "udp4": []netConnectionKindType{kindUDP4}, + "udp6": []netConnectionKindType{kindUDP6}, + "unix": []netConnectionKindType{kindUNIX}, + "inet": []netConnectionKindType{kindTCP4, kindTCP6, kindUDP4, kindUDP6}, + "inet4": []netConnectionKindType{kindTCP4, kindUDP4}, + "inet6": []netConnectionKindType{kindTCP6, kindUDP6}, } type inodeMap struct { pid int32 - fd string + fd uint32 } -type bb struct { - fd int - family int - sockType int - laddr string - raddr string - status string - bound_pid int32 +type connTmp struct { + fd uint32 + family uint32 + sockType uint32 + laddr Addr + raddr Addr + status string + pid int32 + boundPid int32 } // Return a list of network connections opened. @@ -271,38 +293,47 @@ func NetConnectionsPid(kind string, pid int32) ([]NetConnectionStat, error) { inodes, err = getProcInodesAll(root) } else { inodes, err = getProcInodes(root, pid) + if len(inodes) == 0 { + // no connection for the pid + return []NetConnectionStat{}, nil + } } if err != nil { return nil, fmt.Errorf("cound not get pid(s), %d", pid) } - for _, t := range tmap { - fmt.Println(t) - fmt.Println(inodes) + var ret []NetConnectionStat + for _, t := range tmap { var path string - var ls []string + var ls []connTmp + path = fmt.Sprintf("%s/net/%s", root, t.f) switch t.family { case syscall.AF_INET: - path = fmt.Sprintf("%d/net/%s", pid, "tcp") - ls, err = processInet(path, t, inodes, pid) + fallthrough case syscall.AF_INET6: - path = fmt.Sprintf("%d/net/%s", pid, "tcp6") ls, err = processInet(path, t, inodes, pid) case syscall.AF_UNIX: - path = fmt.Sprintf("%d/net/%s", pid, "unix") - ls, err = processInet(path, t, inodes, pid) + ls, err = processUnix(path, t, inodes, pid) } if err != nil { return nil, err } - for _, sss := range ls { - fmt.Println(sss) + for _, c := range ls { + ret = append(ret, NetConnectionStat{ + Fd: c.fd, + Family: t.family, + Type: t.sockType, + Laddr: c.laddr, + Raddr: c.raddr, + Status: c.status, + Pid: c.pid, + }) } } - return []NetConnectionStat{}, nil + return ret, nil } // getProcInodes returnes fd of the pid. @@ -310,7 +341,6 @@ func getProcInodes(root string, pid int32) (map[string][]inodeMap, error) { ret := make(map[string][]inodeMap) dir := fmt.Sprintf("%s/%d/fd", root, pid) - files, err := ioutil.ReadDir(dir) if err != nil { return ret, nil @@ -322,8 +352,6 @@ func getProcInodes(root string, pid int32) (map[string][]inodeMap, error) { if err != nil { continue } - - fmt.Println(inodePath) if strings.HasPrefix(inode, "socket:[") { // the process is using a socket l := len(inode) @@ -334,10 +362,14 @@ func getProcInodes(root string, pid int32) (map[string][]inodeMap, error) { if !ok { ret[inode] = make([]inodeMap, 0) } + fd, err := strconv.Atoi(fd.Name()) + if err != nil { + continue + } i := inodeMap{ pid: pid, - fd: fd.Name(), + fd: uint32(fd), } ret[inode] = append(ret[inode], i) } @@ -390,10 +422,8 @@ func getProcInodesAll(root string) (map[string][]inodeMap, error) { continue } // TODO: update ret. - - fmt.Println(t) + ret = updateMap(ret, t) } - return ret, nil } @@ -401,19 +431,19 @@ func getProcInodesAll(root string) (map[string][]inodeMap, error) { // ex: // "0500000A:0016" -> "10.0.0.5", 22 // "0085002452100113070057A13F025401:0035" -> "2400:8500:1301:1052:a157:7:154:23f", 53 -func decodeAddress(family int, src string) (net.IP, int, error) { +func decodeAddress(family uint32, src string) (Addr, error) { t := strings.Split(src, ":") if len(t) != 2 { - return nil, 0, fmt.Errorf("does not contain port, %s", src) + return Addr{}, fmt.Errorf("does not contain port, %s", src) } addr := t[0] port, err := strconv.ParseInt("0x"+t[1], 0, 64) if err != nil { - return nil, 0, fmt.Errorf("invalid port, %s", src) + return Addr{}, fmt.Errorf("invalid port, %s", src) } decoded, err := hex.DecodeString(addr) if err != nil { - return nil, 0, fmt.Errorf("decode error:", err) + return Addr{}, fmt.Errorf("decode error:", err) } var ip net.IP // Assumes this is little_endian @@ -422,10 +452,13 @@ func decodeAddress(family int, src string) (net.IP, int, error) { } else { // IPv6 ip, err = parseIPv6HexString(decoded) if err != nil { - return nil, 0, err + return Addr{}, err } } - return ip, int(port), nil + return Addr{ + IP: ip.String(), + Port: uint32(port), + }, nil } // Reverse reverses array of bytes. @@ -450,17 +483,18 @@ func parseIPv6HexString(src []byte) (net.IP, error) { return net.IP(buf), nil } -func processInet(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]string, error) { +func processInet(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) { if strings.HasSuffix(file, "6") && !common.PathExists(file) { // IPv6 not supported, return empty. - return []string{}, nil + return []connTmp{}, nil } lines, err := common.ReadLines(file) if err != nil { return nil, err } // skip first line + var ret []connTmp for _, line := range lines[1:] { l := strings.Fields(line) if len(l) < 10 { @@ -469,20 +503,58 @@ func processInet(file string, kind netConnectionKindType, inodes map[string][]in laddr := l[1] raddr := l[2] status := l[3] - inode, err := strconv.Atoi(l[9]) + inode := l[9] + pid := int32(0) + fd := uint32(0) + i, exists := inodes[inode] + if exists { + pid = i[0].pid + fd = i[0].fd + } + if filterPid > 0 && filterPid != pid { + continue + } + if kind.sockType == syscall.SOCK_STREAM { + status = TCPStatuses[status] + } else { + status = "NONE" + } + la, err := decodeAddress(kind.family, laddr) + if err != nil { + continue + } + ra, err := decodeAddress(kind.family, raddr) if err != nil { continue } - fmt.Println(laddr) - fmt.Println(raddr) - fmt.Println(status) - fmt.Println(inode) + + ret = append(ret, connTmp{ + fd: fd, + family: kind.family, + sockType: kind.sockType, + laddr: la, + raddr: ra, + status: status, + pid: pid, + }) } - return nil, nil + return ret, nil } -func processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]string, error) { +func processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) { + + return []connTmp{}, nil +} - return nil, nil +func updateMap(src map[string][]inodeMap, add map[string][]inodeMap) map[string][]inodeMap { + for key, value := range add { + a, exists := src[key] + if !exists { + src[key] = value + continue + } + src[key] = append(a, value...) + } + return src } diff --git a/net/net_linux_test.go b/net/net_linux_test.go index debe16685..79356a033 100644 --- a/net/net_linux_test.go +++ b/net/net_linux_test.go @@ -1,7 +1,6 @@ package net import ( - "fmt" "syscall" "testing" @@ -11,14 +10,12 @@ import ( func TestGetProcInodes(t *testing.T) { root := common.HostProc("") + // checkPid := os.Getpid() // process.test + checkPid := 13378 - // /proc/19957/fd - - v, err := getProcInodes(root, 19957) - if err != nil { - t.Fatal(err) - } - fmt.Println(v) + v, err := getProcInodes(root, int32(checkPid)) + assert.Nil(t, err) + assert.NotEmpty(t, v) } type AddrTest struct { @@ -59,13 +56,13 @@ func TestDecodeAddress(t *testing.T) { if len(src) > 13 { family = syscall.AF_INET6 } - ip, port, err := decodeAddress(family, src) + addr, err := decodeAddress(uint32(family), src) if dst.Error { assert.NotNil(err, src) } else { assert.Nil(err, src) - assert.Equal(dst.IP, ip.String(), src) - assert.Equal(dst.Port, port, src) + assert.Equal(dst.IP, addr.IP, src) + assert.Equal(dst.Port, int(addr.Port), src) } } } From e4ddff09d51eb97209cc77ba0c9a54e0e9f885b7 Mon Sep 17 00:00:00 2001 From: Shirou WAKAYAMA Date: Sat, 5 Mar 2016 22:24:26 +0900 Subject: [PATCH 3/7] [net]linux: add process_unix for NetConnections. --- net/net_linux.go | 56 ++++++++++++++++++++++++++++++++++++++++--- net/net_linux_test.go | 4 ++-- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/net/net_linux.go b/net/net_linux.go index d206f01b0..ad464ed1f 100644 --- a/net/net_linux.go +++ b/net/net_linux.go @@ -273,6 +273,7 @@ type connTmp struct { status string pid int32 boundPid int32 + path string } // Return a list of network connections opened. @@ -320,7 +321,7 @@ func NetConnectionsPid(kind string, pid int32) ([]NetConnectionStat, error) { return nil, err } for _, c := range ls { - ret = append(ret, NetConnectionStat{ + conn := NetConnectionStat{ Fd: c.fd, Family: t.family, Type: t.sockType, @@ -328,7 +329,13 @@ func NetConnectionsPid(kind string, pid int32) ([]NetConnectionStat, error) { Raddr: c.raddr, Status: c.status, Pid: c.pid, - }) + } + if c.pid == 0 { + conn.Pid = c.boundPid + } else { + conn.Pid = c.pid + } + ret = append(ret, conn) } } @@ -493,8 +500,8 @@ func processInet(file string, kind netConnectionKindType, inodes map[string][]in if err != nil { return nil, err } - // skip first line var ret []connTmp + // skip first line for _, line := range lines[1:] { l := strings.Fields(line) if len(l) < 10 { @@ -543,6 +550,49 @@ func processInet(file string, kind netConnectionKindType, inodes map[string][]in } func processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) { + lines, err := common.ReadLines(file) + if err != nil { + return nil, err + } + + var ret []connTmp + // skip first line + for _, line := range lines[1:] { + tokens := strings.Fields(line) + if len(tokens) < 7 { + continue + } + st, err := strconv.Atoi(tokens[4]) + if err != nil { + continue + } + + inode := tokens[6] + + var pairs []inodeMap + pairs, exists := inodes[inode] + if !exists { + pairs = []inodeMap{} + } + for _, pair := range pairs { + if filterPid > 0 && filterPid != pair.pid { + continue + } + var path string + if len(tokens) == 8 { + path = tokens[len(tokens)-1] + } + + ret = append(ret, connTmp{ + family: kind.family, + sockType: uint32(st), + raddr: Addr{}, + pid: pair.pid, + status: "NONE", + path: path, + }) + } + } return []connTmp{}, nil } diff --git a/net/net_linux_test.go b/net/net_linux_test.go index 79356a033..7a2f489db 100644 --- a/net/net_linux_test.go +++ b/net/net_linux_test.go @@ -1,6 +1,7 @@ package net import ( + "os" "syscall" "testing" @@ -10,8 +11,7 @@ import ( func TestGetProcInodes(t *testing.T) { root := common.HostProc("") - // checkPid := os.Getpid() // process.test - checkPid := 13378 + checkPid := os.Getpid() // process.test v, err := getProcInodes(root, int32(checkPid)) assert.Nil(t, err) From 31439aa6b52640499c7d8da79ba3986d525f4b72 Mon Sep 17 00:00:00 2001 From: Shirou WAKAYAMA Date: Sat, 5 Mar 2016 23:53:32 +0900 Subject: [PATCH 4/7] [net]linux: fix valious bugs in NetConnections. --- net/net_linux.go | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/net/net_linux.go b/net/net_linux.go index ad464ed1f..a2006ec13 100644 --- a/net/net_linux.go +++ b/net/net_linux.go @@ -303,6 +303,7 @@ func NetConnectionsPid(kind string, pid int32) ([]NetConnectionStat, error) { return nil, fmt.Errorf("cound not get pid(s), %d", pid) } + dupCheckMap := make(map[string]bool) var ret []NetConnectionStat for _, t := range tmap { @@ -323,8 +324,8 @@ func NetConnectionsPid(kind string, pid int32) ([]NetConnectionStat, error) { for _, c := range ls { conn := NetConnectionStat{ Fd: c.fd, - Family: t.family, - Type: t.sockType, + Family: c.family, + Type: c.sockType, Laddr: c.laddr, Raddr: c.raddr, Status: c.status, @@ -335,7 +336,13 @@ func NetConnectionsPid(kind string, pid int32) ([]NetConnectionStat, error) { } else { conn.Pid = c.pid } - ret = append(ret, conn) + // check duplicate using JSON format + json := conn.String() + _, exists := dupCheckMap[json] + if !exists { + ret = append(ret, conn) + dupCheckMap[json] = true + } } } @@ -359,12 +366,12 @@ func getProcInodes(root string, pid int32) (map[string][]inodeMap, error) { if err != nil { continue } - if strings.HasPrefix(inode, "socket:[") { - // the process is using a socket - l := len(inode) - inode = inode[8 : l-1] + if !strings.HasPrefix(inode, "socket:[") { + continue } - + // the process is using a socket + l := len(inode) + inode = inode[8 : l-1] _, ok := ret[inode] if !ok { ret[inode] = make([]inodeMap, 0) @@ -380,7 +387,6 @@ func getProcInodes(root string, pid int32) (map[string][]inodeMap, error) { } ret[inode] = append(ret[inode], i) } - return ret, nil } @@ -559,12 +565,12 @@ func processUnix(file string, kind netConnectionKindType, inodes map[string][]in // skip first line for _, line := range lines[1:] { tokens := strings.Fields(line) - if len(tokens) < 7 { + if len(tokens) < 6 { continue } st, err := strconv.Atoi(tokens[4]) if err != nil { - continue + return nil, err } inode := tokens[6] @@ -572,7 +578,9 @@ func processUnix(file string, kind netConnectionKindType, inodes map[string][]in var pairs []inodeMap pairs, exists := inodes[inode] if !exists { - pairs = []inodeMap{} + pairs = []inodeMap{ + inodeMap{}, + } } for _, pair := range pairs { if filterPid > 0 && filterPid != pair.pid { @@ -582,19 +590,21 @@ func processUnix(file string, kind netConnectionKindType, inodes map[string][]in if len(tokens) == 8 { path = tokens[len(tokens)-1] } - ret = append(ret, connTmp{ + fd: pair.fd, family: kind.family, sockType: uint32(st), - raddr: Addr{}, - pid: pair.pid, - status: "NONE", - path: path, + laddr: Addr{ + IP: path, + }, + pid: pair.pid, + status: "NONE", + path: path, }) } } - return []connTmp{}, nil + return ret, nil } func updateMap(src map[string][]inodeMap, add map[string][]inodeMap) map[string][]inodeMap { From 32fa88eb4974e58bee6f44afe9c40fc0662ef147 Mon Sep 17 00:00:00 2001 From: Shirou WAKAYAMA Date: Sat, 5 Mar 2016 23:57:18 +0900 Subject: [PATCH 5/7] [net]linux: TestGetProcInodes will fail on CI. --- net/net_linux_test.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/net_linux_test.go b/net/net_linux_test.go index 7a2f489db..23d61a350 100644 --- a/net/net_linux_test.go +++ b/net/net_linux_test.go @@ -1,7 +1,6 @@ package net import ( - "os" "syscall" "testing" @@ -9,11 +8,9 @@ import ( "github.com/stretchr/testify/assert" ) -func TestGetProcInodes(t *testing.T) { +func TestGetProcInodesAll(t *testing.T) { root := common.HostProc("") - checkPid := os.Getpid() // process.test - - v, err := getProcInodes(root, int32(checkPid)) + v, err := getProcInodesAll(root) assert.Nil(t, err) assert.NotEmpty(t, v) } From 567da004c52a71a4d788b6f957254b2b7fa72b60 Mon Sep 17 00:00:00 2001 From: Shirou WAKAYAMA Date: Sun, 6 Mar 2016 00:02:06 +0900 Subject: [PATCH 6/7] [net]linux: explicit skip CI. --- net/net_linux_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/net_linux_test.go b/net/net_linux_test.go index 23d61a350..55f1ec261 100644 --- a/net/net_linux_test.go +++ b/net/net_linux_test.go @@ -1,6 +1,7 @@ package net import ( + "os" "syscall" "testing" @@ -9,6 +10,10 @@ import ( ) func TestGetProcInodesAll(t *testing.T) { + if os.Getenv("CIRCLECI") == "true" { + t.Skip("Skip CI") + } + root := common.HostProc("") v, err := getProcInodesAll(root) assert.Nil(t, err) From 34b63e671bb5ba4fe9a2a937789464b8805bb68e Mon Sep 17 00:00:00 2001 From: Shirou WAKAYAMA Date: Thu, 10 Mar 2016 22:32:16 +0900 Subject: [PATCH 7/7] [net]linux: add a test and fix private field name. --- net/net_linux.go | 18 +++++++++--------- net/net_linux_test.go | 5 +++++ net/net_test.go | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/net/net_linux.go b/net/net_linux.go index a2006ec13..5d538f635 100644 --- a/net/net_linux.go +++ b/net/net_linux.go @@ -217,32 +217,32 @@ var TCPStatuses = map[string]string{ type netConnectionKindType struct { family uint32 sockType uint32 - f string // file name + filename string } var kindTCP4 = netConnectionKindType{ family: syscall.AF_INET, sockType: syscall.SOCK_STREAM, - f: "tcp", + filename: "tcp", } var kindTCP6 = netConnectionKindType{ family: syscall.AF_INET6, sockType: syscall.SOCK_STREAM, - f: "tcp6", + filename: "tcp6", } var kindUDP4 = netConnectionKindType{ family: syscall.AF_INET, sockType: syscall.SOCK_DGRAM, - f: "udp", + filename: "udp", } var kindUDP6 = netConnectionKindType{ family: syscall.AF_INET6, sockType: syscall.SOCK_DGRAM, - f: "udp6", + filename: "udp6", } var kindUNIX = netConnectionKindType{ - family: syscall.AF_UNIX, - f: "unix", + family: syscall.AF_UNIX, + filename: "unix", } var netConnectionKindMap = map[string][]netConnectionKindType{ @@ -309,7 +309,7 @@ func NetConnectionsPid(kind string, pid int32) ([]NetConnectionStat, error) { for _, t := range tmap { var path string var ls []connTmp - path = fmt.Sprintf("%s/net/%s", root, t.f) + path = fmt.Sprintf("%s/net/%s", root, t.filename) switch t.family { case syscall.AF_INET: fallthrough @@ -456,7 +456,7 @@ func decodeAddress(family uint32, src string) (Addr, error) { } decoded, err := hex.DecodeString(addr) if err != nil { - return Addr{}, fmt.Errorf("decode error:", err) + return Addr{}, fmt.Errorf("decode error, %s", err) } var ip net.IP // Assumes this is little_endian diff --git a/net/net_linux_test.go b/net/net_linux_test.go index 55f1ec261..47faeb934 100644 --- a/net/net_linux_test.go +++ b/net/net_linux_test.go @@ -68,3 +68,8 @@ func TestDecodeAddress(t *testing.T) { } } } + +func TestReverse(t *testing.T) { + src := []byte{0x01, 0x02, 0x03} + assert.Equal(t, []byte{0x03, 0x02, 0x01}, Reverse(src)) +} diff --git a/net/net_test.go b/net/net_test.go index 0bac45fef..aabce8174 100644 --- a/net/net_test.go +++ b/net/net_test.go @@ -91,7 +91,7 @@ func TestNetIOCountersPerNic(t *testing.T) { } } -func Test_getNetIOCountersAll(t *testing.T) { +func TestGetNetIOCountersAll(t *testing.T) { n := []NetIOCountersStat{ NetIOCountersStat{ Name: "a",