1
0
mirror of https://github.com/shirou/gopsutil.git synced 2025-04-26 13:48:59 +08:00

[net]linux: implement processInet().

This commit is contained in:
Shirou WAKAYAMA 2016-03-04 23:42:22 +09:00
parent 6c352016d8
commit 32c62b5d48
2 changed files with 143 additions and 74 deletions

View File

@ -199,58 +199,80 @@ func NetFilterCounters() ([]NetFilterStat, error) {
return stats, nil return stats, nil
} }
type netConnectionKindType struct { // http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
family int var TCPStatuses = map[string]string{
sockType int "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",
} }
var KindTCP4 = netConnectionKindType{ type netConnectionKindType struct {
family uint32
sockType uint32
f string // file name
}
var kindTCP4 = netConnectionKindType{
family: syscall.AF_INET, family: syscall.AF_INET,
sockType: syscall.SOCK_STREAM, sockType: syscall.SOCK_STREAM,
f: "tcp",
} }
var KindTCP6 = netConnectionKindType{ var kindTCP6 = netConnectionKindType{
family: syscall.AF_INET6, family: syscall.AF_INET6,
sockType: syscall.SOCK_STREAM, sockType: syscall.SOCK_STREAM,
f: "tcp6",
} }
var KindUDP4 = netConnectionKindType{ var kindUDP4 = netConnectionKindType{
family: syscall.AF_INET, family: syscall.AF_INET,
sockType: syscall.SOCK_DGRAM, sockType: syscall.SOCK_DGRAM,
f: "udp",
} }
var KindUDP6 = netConnectionKindType{ var kindUDP6 = netConnectionKindType{
family: syscall.AF_INET6, family: syscall.AF_INET6,
sockType: syscall.SOCK_DGRAM, sockType: syscall.SOCK_DGRAM,
f: "udp6",
} }
var KindUNIX = netConnectionKindType{ var kindUNIX = netConnectionKindType{
family: syscall.AF_UNIX, family: syscall.AF_UNIX,
f: "unix",
} }
var netConnectionKindMap = map[string][]netConnectionKindType{ var netConnectionKindMap = map[string][]netConnectionKindType{
"all": []netConnectionKindType{KindTCP4, KindTCP6, KindUDP4, KindUDP6, KindUNIX}, "all": []netConnectionKindType{kindTCP4, kindTCP6, kindUDP4, kindUDP6, kindUNIX},
"tcp": []netConnectionKindType{KindTCP4, KindTCP6}, "tcp": []netConnectionKindType{kindTCP4, kindTCP6},
"tcp4": []netConnectionKindType{KindTCP4}, "tcp4": []netConnectionKindType{kindTCP4},
"tcp6": []netConnectionKindType{KindTCP6}, "tcp6": []netConnectionKindType{kindTCP6},
"udp": []netConnectionKindType{KindUDP4, KindUDP6}, "udp": []netConnectionKindType{kindUDP4, kindUDP6},
"udp4": []netConnectionKindType{KindUDP4}, "udp4": []netConnectionKindType{kindUDP4},
"udp6": []netConnectionKindType{KindUDP6}, "udp6": []netConnectionKindType{kindUDP6},
"unix": []netConnectionKindType{KindUNIX}, "unix": []netConnectionKindType{kindUNIX},
"inet": []netConnectionKindType{KindTCP4, KindTCP6, KindUDP4, KindUDP6}, "inet": []netConnectionKindType{kindTCP4, kindTCP6, kindUDP4, kindUDP6},
"inet4": []netConnectionKindType{KindTCP4, KindUDP4}, "inet4": []netConnectionKindType{kindTCP4, kindUDP4},
"inet6": []netConnectionKindType{KindTCP6, KindUDP6}, "inet6": []netConnectionKindType{kindTCP6, kindUDP6},
} }
type inodeMap struct { type inodeMap struct {
pid int32 pid int32
fd string fd uint32
} }
type bb struct { type connTmp struct {
fd int fd uint32
family int family uint32
sockType int sockType uint32
laddr string laddr Addr
raddr string raddr Addr
status string status string
bound_pid int32 pid int32
boundPid int32
} }
// Return a list of network connections opened. // Return a list of network connections opened.
@ -271,38 +293,47 @@ func NetConnectionsPid(kind string, pid int32) ([]NetConnectionStat, error) {
inodes, err = getProcInodesAll(root) inodes, err = getProcInodesAll(root)
} else { } else {
inodes, err = getProcInodes(root, pid) inodes, err = getProcInodes(root, pid)
if len(inodes) == 0 {
// no connection for the pid
return []NetConnectionStat{}, nil
}
} }
if err != nil { if err != nil {
return nil, fmt.Errorf("cound not get pid(s), %d", pid) return nil, fmt.Errorf("cound not get pid(s), %d", pid)
} }
for _, t := range tmap { var ret []NetConnectionStat
fmt.Println(t)
fmt.Println(inodes)
for _, t := range tmap {
var path string var path string
var ls []string var ls []connTmp
path = fmt.Sprintf("%s/net/%s", root, t.f)
switch t.family { switch t.family {
case syscall.AF_INET: case syscall.AF_INET:
path = fmt.Sprintf("%d/net/%s", pid, "tcp") fallthrough
ls, err = processInet(path, t, inodes, pid)
case syscall.AF_INET6: case syscall.AF_INET6:
path = fmt.Sprintf("%d/net/%s", pid, "tcp6")
ls, err = processInet(path, t, inodes, pid) ls, err = processInet(path, t, inodes, pid)
case syscall.AF_UNIX: case syscall.AF_UNIX:
path = fmt.Sprintf("%d/net/%s", pid, "unix") ls, err = processUnix(path, t, inodes, pid)
ls, err = processInet(path, t, inodes, pid)
} }
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, sss := range ls { for _, c := range ls {
fmt.Println(sss) 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. // 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) ret := make(map[string][]inodeMap)
dir := fmt.Sprintf("%s/%d/fd", root, pid) dir := fmt.Sprintf("%s/%d/fd", root, pid)
files, err := ioutil.ReadDir(dir) files, err := ioutil.ReadDir(dir)
if err != nil { if err != nil {
return ret, nil return ret, nil
@ -322,8 +352,6 @@ func getProcInodes(root string, pid int32) (map[string][]inodeMap, error) {
if err != nil { if err != nil {
continue continue
} }
fmt.Println(inodePath)
if strings.HasPrefix(inode, "socket:[") { if strings.HasPrefix(inode, "socket:[") {
// the process is using a socket // the process is using a socket
l := len(inode) l := len(inode)
@ -334,10 +362,14 @@ func getProcInodes(root string, pid int32) (map[string][]inodeMap, error) {
if !ok { if !ok {
ret[inode] = make([]inodeMap, 0) ret[inode] = make([]inodeMap, 0)
} }
fd, err := strconv.Atoi(fd.Name())
if err != nil {
continue
}
i := inodeMap{ i := inodeMap{
pid: pid, pid: pid,
fd: fd.Name(), fd: uint32(fd),
} }
ret[inode] = append(ret[inode], i) ret[inode] = append(ret[inode], i)
} }
@ -390,10 +422,8 @@ func getProcInodesAll(root string) (map[string][]inodeMap, error) {
continue continue
} }
// TODO: update ret. // TODO: update ret.
ret = updateMap(ret, t)
fmt.Println(t)
} }
return ret, nil return ret, nil
} }
@ -401,19 +431,19 @@ func getProcInodesAll(root string) (map[string][]inodeMap, error) {
// ex: // ex:
// "0500000A:0016" -> "10.0.0.5", 22 // "0500000A:0016" -> "10.0.0.5", 22
// "0085002452100113070057A13F025401:0035" -> "2400:8500:1301:1052:a157:7:154:23f", 53 // "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, ":") t := strings.Split(src, ":")
if len(t) != 2 { 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] addr := t[0]
port, err := strconv.ParseInt("0x"+t[1], 0, 64) port, err := strconv.ParseInt("0x"+t[1], 0, 64)
if err != nil { 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) decoded, err := hex.DecodeString(addr)
if err != nil { if err != nil {
return nil, 0, fmt.Errorf("decode error:", err) return Addr{}, fmt.Errorf("decode error:", err)
} }
var ip net.IP var ip net.IP
// Assumes this is little_endian // Assumes this is little_endian
@ -422,10 +452,13 @@ func decodeAddress(family int, src string) (net.IP, int, error) {
} else { // IPv6 } else { // IPv6
ip, err = parseIPv6HexString(decoded) ip, err = parseIPv6HexString(decoded)
if err != nil { 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. // Reverse reverses array of bytes.
@ -450,17 +483,18 @@ func parseIPv6HexString(src []byte) (net.IP, error) {
return net.IP(buf), nil 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) { if strings.HasSuffix(file, "6") && !common.PathExists(file) {
// IPv6 not supported, return empty. // IPv6 not supported, return empty.
return []string{}, nil return []connTmp{}, nil
} }
lines, err := common.ReadLines(file) lines, err := common.ReadLines(file)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// skip first line // skip first line
var ret []connTmp
for _, line := range lines[1:] { for _, line := range lines[1:] {
l := strings.Fields(line) l := strings.Fields(line)
if len(l) < 10 { if len(l) < 10 {
@ -469,20 +503,58 @@ func processInet(file string, kind netConnectionKindType, inodes map[string][]in
laddr := l[1] laddr := l[1]
raddr := l[2] raddr := l[2]
status := l[3] 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 { if err != nil {
continue continue
} }
fmt.Println(laddr) ra, err := decodeAddress(kind.family, raddr)
fmt.Println(raddr) if err != nil {
fmt.Println(status) continue
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 nil, nil return []connTmp{}, 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
} }

View File

@ -1,7 +1,6 @@
package net package net
import ( import (
"fmt"
"syscall" "syscall"
"testing" "testing"
@ -11,14 +10,12 @@ import (
func TestGetProcInodes(t *testing.T) { func TestGetProcInodes(t *testing.T) {
root := common.HostProc("") root := common.HostProc("")
// checkPid := os.Getpid() // process.test
checkPid := 13378
// /proc/19957/fd v, err := getProcInodes(root, int32(checkPid))
assert.Nil(t, err)
v, err := getProcInodes(root, 19957) assert.NotEmpty(t, v)
if err != nil {
t.Fatal(err)
}
fmt.Println(v)
} }
type AddrTest struct { type AddrTest struct {
@ -59,13 +56,13 @@ func TestDecodeAddress(t *testing.T) {
if len(src) > 13 { if len(src) > 13 {
family = syscall.AF_INET6 family = syscall.AF_INET6
} }
ip, port, err := decodeAddress(family, src) addr, err := decodeAddress(uint32(family), src)
if dst.Error { if dst.Error {
assert.NotNil(err, src) assert.NotNil(err, src)
} else { } else {
assert.Nil(err, src) assert.Nil(err, src)
assert.Equal(dst.IP, ip.String(), src) assert.Equal(dst.IP, addr.IP, src)
assert.Equal(dst.Port, port, src) assert.Equal(dst.Port, int(addr.Port), src)
} }
} }
} }