mirror of https://github.com/golang/go.git
net/internal/socktest: add hook for Listen, failed system call counters
Change-Id: Icaac9a48a3b9a3c5542235162e21ab8303592965 Reviewed-on: https://go-review.googlesource.com/8641 Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
e629cd0f88
commit
130e3f9a32
|
|
@ -5,7 +5,10 @@
|
|||
// Package socktest provides utilities for socket testing.
|
||||
package socktest
|
||||
|
||||
import "sync"
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func switchInit(sw *Switch) {
|
||||
sw.fltab = make(map[FilterType]Filter)
|
||||
|
|
@ -70,7 +73,11 @@ func cookie(family, sotype, proto int) Cookie {
|
|||
type Status struct {
|
||||
Cookie Cookie
|
||||
Err error // error status of socket system call
|
||||
SocketErr int // error status of socket by SO_ERROR
|
||||
SocketErr error // error status of socket by SO_ERROR
|
||||
}
|
||||
|
||||
func (so Status) String() string {
|
||||
return fmt.Sprintf("(%s, %s, %s): syscallerr=%v, socketerr=%v", familyString(so.Cookie.Family()), typeString(so.Cookie.Type()), protocolString(so.Cookie.Protocol()), so.Err, so.SocketErr)
|
||||
}
|
||||
|
||||
// A Stat represents a per-cookie socket statistics.
|
||||
|
|
@ -80,9 +87,20 @@ type Stat struct {
|
|||
Protocol int // protocol number
|
||||
|
||||
Opened uint64 // number of sockets opened
|
||||
Accepted uint64 // number of sockets accepted
|
||||
Connected uint64 // number of sockets connected
|
||||
Listened uint64 // number of sockets listened
|
||||
Accepted uint64 // number of sockets accepted
|
||||
Closed uint64 // number of sockets closed
|
||||
|
||||
OpenFailed uint64 // number of sockets open failed
|
||||
ConnectFailed uint64 // number of sockets connect failed
|
||||
ListenFailed uint64 // number of sockets listen failed
|
||||
AcceptFailed uint64 // number of sockets accept failed
|
||||
CloseFailed uint64 // number of sockets close failed
|
||||
}
|
||||
|
||||
func (st Stat) String() string {
|
||||
return fmt.Sprintf("(%s, %s, %s): opened=%d, connected=%d, listened=%d, accepted=%d, closed=%d, openfailed=%d, connectfailed=%d, listenfailed=%d, acceptfailed=%d, closefailed=%d", familyString(st.Family), typeString(st.Type), protocolString(st.Protocol), st.Opened, st.Connected, st.Listened, st.Accepted, st.Closed, st.OpenFailed, st.ConnectFailed, st.ListenFailed, st.AcceptFailed, st.CloseFailed)
|
||||
}
|
||||
|
||||
type stats map[Cookie]*Stat
|
||||
|
|
@ -101,8 +119,9 @@ type FilterType int
|
|||
|
||||
const (
|
||||
FilterSocket FilterType = iota // for Socket
|
||||
FilterAccept // for Accept or Accept4
|
||||
FilterConnect // for Connect or ConnectEx
|
||||
FilterListen // for Listen
|
||||
FilterAccept // for Accept or Accept4
|
||||
FilterGetsockoptInt // for GetsockoptInt
|
||||
FilterClose // for Close or Closesocket
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !plan9
|
||||
|
||||
package socktest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func familyString(family int) string {
|
||||
switch family {
|
||||
case syscall.AF_INET:
|
||||
return "inet4"
|
||||
case syscall.AF_INET6:
|
||||
return "inet6"
|
||||
case syscall.AF_UNIX:
|
||||
return "local"
|
||||
default:
|
||||
return fmt.Sprintf("%d", family)
|
||||
}
|
||||
}
|
||||
|
||||
func typeString(sotype int) string {
|
||||
var s string
|
||||
switch sotype & 0xff {
|
||||
case syscall.SOCK_STREAM:
|
||||
s = "stream"
|
||||
case syscall.SOCK_DGRAM:
|
||||
s = "datagram"
|
||||
case syscall.SOCK_RAW:
|
||||
s = "raw"
|
||||
case syscall.SOCK_SEQPACKET:
|
||||
s = "seqpacket"
|
||||
default:
|
||||
s = fmt.Sprintf("%d", sotype&0xff)
|
||||
}
|
||||
if flags := uint(sotype) & ^uint(0xff); flags != 0 {
|
||||
s += fmt.Sprintf("|%#x", flags)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func protocolString(proto int) string {
|
||||
switch proto {
|
||||
case 0:
|
||||
return "default"
|
||||
case syscall.IPPROTO_TCP:
|
||||
return "tcp"
|
||||
case syscall.IPPROTO_UDP:
|
||||
return "udp"
|
||||
default:
|
||||
return fmt.Sprintf("%d", proto)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,3 +8,9 @@ package socktest
|
|||
|
||||
// Sockets maps a socket descriptor to the status of socket.
|
||||
type Sockets map[int]Status
|
||||
|
||||
func familyString(family int) string { return "<nil>" }
|
||||
|
||||
func typeString(sotype int) string { return "<nil>" }
|
||||
|
||||
func protocolString(proto int) string { return "<nil>" }
|
||||
|
|
|
|||
|
|
@ -30,12 +30,13 @@ func (sw *Switch) Accept4(s, flags int) (ns int, sa syscall.Sockaddr, err error)
|
|||
return -1, nil, err
|
||||
}
|
||||
|
||||
sw.smu.Lock()
|
||||
defer sw.smu.Unlock()
|
||||
if so.Err != nil {
|
||||
sw.stats.getLocked(so.Cookie).AcceptFailed++
|
||||
return -1, nil, so.Err
|
||||
}
|
||||
sw.smu.Lock()
|
||||
nso := sw.addLocked(ns, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol())
|
||||
sw.stats.getLocked(nso.Cookie).Accepted++
|
||||
sw.smu.Unlock()
|
||||
return ns, sa, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,13 +27,14 @@ func (sw *Switch) Socket(family, sotype, proto int) (s int, err error) {
|
|||
return -1, err
|
||||
}
|
||||
|
||||
sw.smu.Lock()
|
||||
defer sw.smu.Unlock()
|
||||
if so.Err != nil {
|
||||
sw.stats.getLocked(so.Cookie).OpenFailed++
|
||||
return -1, so.Err
|
||||
}
|
||||
sw.smu.Lock()
|
||||
nso := sw.addLocked(s, family, sotype, proto)
|
||||
sw.stats.getLocked(nso.Cookie).Opened++
|
||||
sw.smu.Unlock()
|
||||
return s, nil
|
||||
}
|
||||
|
||||
|
|
@ -56,13 +57,14 @@ func (sw *Switch) Close(s int) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
sw.smu.Lock()
|
||||
defer sw.smu.Unlock()
|
||||
if so.Err != nil {
|
||||
sw.stats.getLocked(so.Cookie).CloseFailed++
|
||||
return so.Err
|
||||
}
|
||||
sw.smu.Lock()
|
||||
delete(sw.sotab, s)
|
||||
sw.stats.getLocked(so.Cookie).Closed++
|
||||
sw.smu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -85,12 +87,42 @@ func (sw *Switch) Connect(s int, sa syscall.Sockaddr) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
sw.smu.Lock()
|
||||
defer sw.smu.Unlock()
|
||||
if so.Err != nil {
|
||||
sw.stats.getLocked(so.Cookie).ConnectFailed++
|
||||
return so.Err
|
||||
}
|
||||
sw.smu.Lock()
|
||||
sw.stats.getLocked(so.Cookie).Connected++
|
||||
sw.smu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Listen wraps syscall.Listen.
|
||||
func (sw *Switch) Listen(s, backlog int) (err error) {
|
||||
so := sw.sockso(s)
|
||||
if so == nil {
|
||||
return syscall.Listen(s, backlog)
|
||||
}
|
||||
sw.fmu.RLock()
|
||||
f, _ := sw.fltab[FilterListen]
|
||||
sw.fmu.RUnlock()
|
||||
|
||||
af, err := f.apply(so)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
so.Err = syscall.Listen(s, backlog)
|
||||
if err = af.apply(so); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sw.smu.Lock()
|
||||
defer sw.smu.Unlock()
|
||||
if so.Err != nil {
|
||||
sw.stats.getLocked(so.Cookie).ListenFailed++
|
||||
return so.Err
|
||||
}
|
||||
sw.stats.getLocked(so.Cookie).Listened++
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -116,13 +148,14 @@ func (sw *Switch) Accept(s int) (ns int, sa syscall.Sockaddr, err error) {
|
|||
return -1, nil, err
|
||||
}
|
||||
|
||||
sw.smu.Lock()
|
||||
defer sw.smu.Unlock()
|
||||
if so.Err != nil {
|
||||
sw.stats.getLocked(so.Cookie).AcceptFailed++
|
||||
return -1, nil, so.Err
|
||||
}
|
||||
sw.smu.Lock()
|
||||
nso := sw.addLocked(ns, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol())
|
||||
sw.stats.getLocked(nso.Cookie).Accepted++
|
||||
sw.smu.Unlock()
|
||||
return ns, sa, nil
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +173,8 @@ func (sw *Switch) GetsockoptInt(s, level, opt int) (soerr int, err error) {
|
|||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
so.SocketErr, so.Err = syscall.GetsockoptInt(s, level, opt)
|
||||
soerr, so.Err = syscall.GetsockoptInt(s, level, opt)
|
||||
so.SocketErr = syscall.Errno(soerr)
|
||||
if err = af.apply(so); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
|
@ -148,10 +182,10 @@ func (sw *Switch) GetsockoptInt(s, level, opt int) (soerr int, err error) {
|
|||
if so.Err != nil {
|
||||
return -1, so.Err
|
||||
}
|
||||
if opt == syscall.SO_ERROR && (so.SocketErr == 0 || syscall.Errno(so.SocketErr) == syscall.EISCONN) {
|
||||
if opt == syscall.SO_ERROR && (so.SocketErr == syscall.Errno(0) || so.SocketErr == syscall.EISCONN) {
|
||||
sw.smu.Lock()
|
||||
sw.stats.getLocked(so.Cookie).Connected++
|
||||
sw.smu.Unlock()
|
||||
}
|
||||
return so.SocketErr, nil
|
||||
return soerr, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,13 +25,14 @@ func (sw *Switch) Socket(family, sotype, proto int) (s syscall.Handle, err error
|
|||
return syscall.InvalidHandle, err
|
||||
}
|
||||
|
||||
sw.smu.Lock()
|
||||
defer sw.smu.Unlock()
|
||||
if so.Err != nil {
|
||||
sw.stats.getLocked(so.Cookie).OpenFailed++
|
||||
return syscall.InvalidHandle, so.Err
|
||||
}
|
||||
sw.smu.Lock()
|
||||
nso := sw.addLocked(s, family, sotype, proto)
|
||||
sw.stats.getLocked(nso.Cookie).Opened++
|
||||
sw.smu.Unlock()
|
||||
return s, nil
|
||||
}
|
||||
|
||||
|
|
@ -54,13 +55,14 @@ func (sw *Switch) Closesocket(s syscall.Handle) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
sw.smu.Lock()
|
||||
defer sw.smu.Unlock()
|
||||
if so.Err != nil {
|
||||
sw.stats.getLocked(so.Cookie).CloseFailed++
|
||||
return so.Err
|
||||
}
|
||||
sw.smu.Lock()
|
||||
delete(sw.sotab, s)
|
||||
sw.stats.getLocked(so.Cookie).Closed++
|
||||
sw.smu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -83,12 +85,13 @@ func (sw *Switch) Connect(s syscall.Handle, sa syscall.Sockaddr) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
sw.smu.Lock()
|
||||
defer sw.smu.Unlock()
|
||||
if so.Err != nil {
|
||||
sw.stats.getLocked(so.Cookie).ConnectFailed++
|
||||
return so.Err
|
||||
}
|
||||
sw.smu.Lock()
|
||||
sw.stats.getLocked(so.Cookie).Connected++
|
||||
sw.smu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -111,11 +114,41 @@ func (sw *Switch) ConnectEx(s syscall.Handle, sa syscall.Sockaddr, b *byte, n ui
|
|||
return err
|
||||
}
|
||||
|
||||
sw.smu.Lock()
|
||||
defer sw.smu.Unlock()
|
||||
if so.Err != nil {
|
||||
sw.stats.getLocked(so.Cookie).ConnectFailed++
|
||||
return so.Err
|
||||
}
|
||||
sw.smu.Lock()
|
||||
sw.stats.getLocked(so.Cookie).Connected++
|
||||
sw.smu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Listen wraps syscall.Listen.
|
||||
func (sw *Switch) Listen(s syscall.Handle, backlog int) (err error) {
|
||||
so := sw.sockso(s)
|
||||
if so == nil {
|
||||
return syscall.Listen(s, backlog)
|
||||
}
|
||||
sw.fmu.RLock()
|
||||
f, _ := sw.fltab[FilterListen]
|
||||
sw.fmu.RUnlock()
|
||||
|
||||
af, err := f.apply(so)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
so.Err = syscall.Listen(s, backlog)
|
||||
if err = af.apply(so); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sw.smu.Lock()
|
||||
defer sw.smu.Unlock()
|
||||
if so.Err != nil {
|
||||
sw.stats.getLocked(so.Cookie).ListenFailed++
|
||||
return so.Err
|
||||
}
|
||||
sw.stats.getLocked(so.Cookie).Listened++
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue