From 130e3f9a324a51b62c63a772fd0a73e79693c8ab Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Wed, 8 Apr 2015 20:13:36 +0900 Subject: [PATCH] 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 --- src/net/internal/socktest/switch.go | 27 +++++++++-- src/net/internal/socktest/switch_posix.go | 58 +++++++++++++++++++++++ src/net/internal/socktest/switch_stub.go | 6 +++ src/net/internal/socktest/sys_cloexec.go | 5 +- src/net/internal/socktest/sys_unix.go | 56 +++++++++++++++++----- src/net/internal/socktest/sys_windows.go | 49 +++++++++++++++---- 6 files changed, 176 insertions(+), 25 deletions(-) create mode 100644 src/net/internal/socktest/switch_posix.go diff --git a/src/net/internal/socktest/switch.go b/src/net/internal/socktest/switch.go index 539819160e..5e558a2de3 100644 --- a/src/net/internal/socktest/switch.go +++ b/src/net/internal/socktest/switch.go @@ -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 ) diff --git a/src/net/internal/socktest/switch_posix.go b/src/net/internal/socktest/switch_posix.go new file mode 100644 index 0000000000..863edef0d3 --- /dev/null +++ b/src/net/internal/socktest/switch_posix.go @@ -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) + } +} diff --git a/src/net/internal/socktest/switch_stub.go b/src/net/internal/socktest/switch_stub.go index be97628a00..28ce72cb85 100644 --- a/src/net/internal/socktest/switch_stub.go +++ b/src/net/internal/socktest/switch_stub.go @@ -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 "" } + +func typeString(sotype int) string { return "" } + +func protocolString(proto int) string { return "" } diff --git a/src/net/internal/socktest/sys_cloexec.go b/src/net/internal/socktest/sys_cloexec.go index 61cb6aec08..340ff071e7 100644 --- a/src/net/internal/socktest/sys_cloexec.go +++ b/src/net/internal/socktest/sys_cloexec.go @@ -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 } diff --git a/src/net/internal/socktest/sys_unix.go b/src/net/internal/socktest/sys_unix.go index b128c019ae..4089f8cea2 100644 --- a/src/net/internal/socktest/sys_unix.go +++ b/src/net/internal/socktest/sys_unix.go @@ -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 } diff --git a/src/net/internal/socktest/sys_windows.go b/src/net/internal/socktest/sys_windows.go index 30bac45512..907e01b5a2 100644 --- a/src/net/internal/socktest/sys_windows.go +++ b/src/net/internal/socktest/sys_windows.go @@ -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 } -- 2.48.1