Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Canread
Gopsutil
提交
4dfd293f
G
Gopsutil
项目概览
Canread
/
Gopsutil
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
Gopsutil
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
4dfd293f
编写于
3月 12, 2016
作者:
S
shirou
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #169 from shirou/net/replace_lsof
[net]linux: start replacing lsof
上级
627d2a98
34b63e67
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
513 addition
and
2 deletion
+513
-2
internal/common/common.go
internal/common/common.go
+10
-0
net/net_linux.go
net/net_linux.go
+426
-0
net/net_linux_test.go
net/net_linux_test.go
+75
-0
net/net_test.go
net/net_test.go
+1
-1
net/net_unix.go
net/net_unix.go
+1
-1
未找到文件。
internal/common/common.go
浏览文件 @
4dfd293f
...
@@ -206,6 +206,16 @@ func StringsContains(target []string, src string) bool {
...
@@ -206,6 +206,16 @@ func StringsContains(target []string, src string) bool {
return
false
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.
// get struct attributes.
// This method is used only for debugging platform dependent code.
// This method is used only for debugging platform dependent code.
func
attributes
(
m
interface
{})
map
[
string
]
reflect
.
Type
{
func
attributes
(
m
interface
{})
map
[
string
]
reflect
.
Type
{
...
...
net/net_linux.go
浏览文件 @
4dfd293f
...
@@ -3,9 +3,15 @@
...
@@ -3,9 +3,15 @@
package
net
package
net
import
(
import
(
"encoding/hex"
"errors"
"errors"
"fmt"
"io/ioutil"
"net"
"os"
"strconv"
"strconv"
"strings"
"strings"
"syscall"
"github.com/shirou/gopsutil/internal/common"
"github.com/shirou/gopsutil/internal/common"
)
)
...
@@ -192,3 +198,423 @@ func NetFilterCounters() ([]NetFilterStat, error) {
...
@@ -192,3 +198,423 @@ func NetFilterCounters() ([]NetFilterStat, error) {
stats
=
append
(
stats
,
payload
)
stats
=
append
(
stats
,
payload
)
return
stats
,
nil
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
uint32
sockType
uint32
filename
string
}
var
kindTCP4
=
netConnectionKindType
{
family
:
syscall
.
AF_INET
,
sockType
:
syscall
.
SOCK_STREAM
,
filename
:
"tcp"
,
}
var
kindTCP6
=
netConnectionKindType
{
family
:
syscall
.
AF_INET6
,
sockType
:
syscall
.
SOCK_STREAM
,
filename
:
"tcp6"
,
}
var
kindUDP4
=
netConnectionKindType
{
family
:
syscall
.
AF_INET
,
sockType
:
syscall
.
SOCK_DGRAM
,
filename
:
"udp"
,
}
var
kindUDP6
=
netConnectionKindType
{
family
:
syscall
.
AF_INET6
,
sockType
:
syscall
.
SOCK_DGRAM
,
filename
:
"udp6"
,
}
var
kindUNIX
=
netConnectionKindType
{
family
:
syscall
.
AF_UNIX
,
filename
:
"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
uint32
}
type
connTmp
struct
{
fd
uint32
family
uint32
sockType
uint32
laddr
Addr
raddr
Addr
status
string
pid
int32
boundPid
int32
path
string
}
// 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
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
)
}
dupCheckMap
:=
make
(
map
[
string
]
bool
)
var
ret
[]
NetConnectionStat
for
_
,
t
:=
range
tmap
{
var
path
string
var
ls
[]
connTmp
path
=
fmt
.
Sprintf
(
"%s/net/%s"
,
root
,
t
.
filename
)
switch
t
.
family
{
case
syscall
.
AF_INET
:
fallthrough
case
syscall
.
AF_INET6
:
ls
,
err
=
processInet
(
path
,
t
,
inodes
,
pid
)
case
syscall
.
AF_UNIX
:
ls
,
err
=
processUnix
(
path
,
t
,
inodes
,
pid
)
}
if
err
!=
nil
{
return
nil
,
err
}
for
_
,
c
:=
range
ls
{
conn
:=
NetConnectionStat
{
Fd
:
c
.
fd
,
Family
:
c
.
family
,
Type
:
c
.
sockType
,
Laddr
:
c
.
laddr
,
Raddr
:
c
.
raddr
,
Status
:
c
.
status
,
Pid
:
c
.
pid
,
}
if
c
.
pid
==
0
{
conn
.
Pid
=
c
.
boundPid
}
else
{
conn
.
Pid
=
c
.
pid
}
// check duplicate using JSON format
json
:=
conn
.
String
()
_
,
exists
:=
dupCheckMap
[
json
]
if
!
exists
{
ret
=
append
(
ret
,
conn
)
dupCheckMap
[
json
]
=
true
}
}
}
return
ret
,
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
}
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
)
}
fd
,
err
:=
strconv
.
Atoi
(
fd
.
Name
())
if
err
!=
nil
{
continue
}
i
:=
inodeMap
{
pid
:
pid
,
fd
:
uint32
(
fd
),
}
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.
ret
=
updateMap
(
ret
,
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
uint32
,
src
string
)
(
Addr
,
error
)
{
t
:=
strings
.
Split
(
src
,
":"
)
if
len
(
t
)
!=
2
{
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
Addr
{},
fmt
.
Errorf
(
"invalid port, %s"
,
src
)
}
decoded
,
err
:=
hex
.
DecodeString
(
addr
)
if
err
!=
nil
{
return
Addr
{},
fmt
.
Errorf
(
"decode error, %s"
,
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
Addr
{},
err
}
}
return
Addr
{
IP
:
ip
.
String
(),
Port
:
uint32
(
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
)
([]
connTmp
,
error
)
{
if
strings
.
HasSuffix
(
file
,
"6"
)
&&
!
common
.
PathExists
(
file
)
{
// IPv6 not supported, return empty.
return
[]
connTmp
{},
nil
}
lines
,
err
:=
common
.
ReadLines
(
file
)
if
err
!=
nil
{
return
nil
,
err
}
var
ret
[]
connTmp
// 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
:=
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
}
ret
=
append
(
ret
,
connTmp
{
fd
:
fd
,
family
:
kind
.
family
,
sockType
:
kind
.
sockType
,
laddr
:
la
,
raddr
:
ra
,
status
:
status
,
pid
:
pid
,
})
}
return
ret
,
nil
}
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
)
<
6
{
continue
}
st
,
err
:=
strconv
.
Atoi
(
tokens
[
4
])
if
err
!=
nil
{
return
nil
,
err
}
inode
:=
tokens
[
6
]
var
pairs
[]
inodeMap
pairs
,
exists
:=
inodes
[
inode
]
if
!
exists
{
pairs
=
[]
inodeMap
{
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
{
fd
:
pair
.
fd
,
family
:
kind
.
family
,
sockType
:
uint32
(
st
),
laddr
:
Addr
{
IP
:
path
,
},
pid
:
pair
.
pid
,
status
:
"NONE"
,
path
:
path
,
})
}
}
return
ret
,
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
}
net/net_linux_test.go
0 → 100644
浏览文件 @
4dfd293f
package
net
import
(
"os"
"syscall"
"testing"
"github.com/shirou/gopsutil/internal/common"
"github.com/stretchr/testify/assert"
)
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
)
assert
.
NotEmpty
(
t
,
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
}
addr
,
err
:=
decodeAddress
(
uint32
(
family
),
src
)
if
dst
.
Error
{
assert
.
NotNil
(
err
,
src
)
}
else
{
assert
.
Nil
(
err
,
src
)
assert
.
Equal
(
dst
.
IP
,
addr
.
IP
,
src
)
assert
.
Equal
(
dst
.
Port
,
int
(
addr
.
Port
),
src
)
}
}
}
func
TestReverse
(
t
*
testing
.
T
)
{
src
:=
[]
byte
{
0x01
,
0x02
,
0x03
}
assert
.
Equal
(
t
,
[]
byte
{
0x03
,
0x02
,
0x01
},
Reverse
(
src
))
}
net/net_test.go
浏览文件 @
4dfd293f
...
@@ -91,7 +91,7 @@ func TestNetIOCountersPerNic(t *testing.T) {
...
@@ -91,7 +91,7 @@ func TestNetIOCountersPerNic(t *testing.T) {
}
}
}
}
func
Test
_g
etNetIOCountersAll
(
t
*
testing
.
T
)
{
func
Test
G
etNetIOCountersAll
(
t
*
testing
.
T
)
{
n
:=
[]
NetIOCountersStat
{
n
:=
[]
NetIOCountersStat
{
NetIOCountersStat
{
NetIOCountersStat
{
Name
:
"a"
,
Name
:
"a"
,
...
...
net/net_unix.go
浏览文件 @
4dfd293f
// +build
linux
freebsd darwin
// +build freebsd darwin
package
net
package
net
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录