Skip to content

Commit afd2d2b

Browse files
committed
net: add Source field to OpError
Not only by network, transport-layer intermediaries but by virtualization stuff in a node, it is hard to identify the root cause of weird faults without information of packet flows after disaster happened. This change adds Source field to OpError to be able to represent a 5-tuple of internet transport protocols for helping dealing with complicated systems. Also clarifies the usage of Source and Addr fields. Updates #4856. Change-Id: I96a523fe391ed14406bfb21604c461d4aac2fa19 Reviewed-on: https://go-review.googlesource.com/9231 Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 3574891 commit afd2d2b

16 files changed

+218
-234
lines changed

src/net/dial.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ func DialTimeout(network, address string, timeout time.Duration) (Conn, error) {
161161
func (d *Dialer) Dial(network, address string) (Conn, error) {
162162
addrs, err := resolveAddrList("dial", network, address, d.deadline())
163163
if err != nil {
164-
return nil, &OpError{Op: "dial", Net: network, Addr: nil, Err: err}
164+
return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
165165
}
166166
var dialer func(deadline time.Time) (Conn, error)
167167
if d.DualStack && network == "tcp" {
@@ -235,7 +235,7 @@ func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Con
235235
// the destination address.
236236
func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error) {
237237
if la != nil && la.Network() != ra.Network() {
238-
return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
238+
return nil, &OpError{Op: "dial", Net: net, Source: la, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
239239
}
240240
switch ra := ra.(type) {
241241
case *TCPAddr:
@@ -251,7 +251,7 @@ func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err
251251
la, _ := la.(*UnixAddr)
252252
c, err = dialUnix(net, la, ra, deadline)
253253
default:
254-
return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: addr}}
254+
return nil, &OpError{Op: "dial", Net: net, Source: la, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: addr}}
255255
}
256256
if err != nil {
257257
return nil, err // c is non-nil interface containing nil pointer
@@ -266,7 +266,7 @@ func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err
266266
func Listen(net, laddr string) (Listener, error) {
267267
addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
268268
if err != nil {
269-
return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
269+
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
270270
}
271271
var l Listener
272272
switch la := addrs.first(isIPv4).(type) {
@@ -275,7 +275,7 @@ func Listen(net, laddr string) (Listener, error) {
275275
case *UnixAddr:
276276
l, err = ListenUnix(net, la)
277277
default:
278-
return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
278+
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
279279
}
280280
if err != nil {
281281
return nil, err // l is non-nil interface containing nil pointer
@@ -290,7 +290,7 @@ func Listen(net, laddr string) (Listener, error) {
290290
func ListenPacket(net, laddr string) (PacketConn, error) {
291291
addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
292292
if err != nil {
293-
return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
293+
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
294294
}
295295
var l PacketConn
296296
switch la := addrs.first(isIPv4).(type) {
@@ -301,7 +301,7 @@ func ListenPacket(net, laddr string) (PacketConn, error) {
301301
case *UnixAddr:
302302
l, err = ListenUnixgram(net, la)
303303
default:
304-
return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
304+
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
305305
}
306306
if err != nil {
307307
return nil, err // l is non-nil interface containing nil pointer

src/net/dial_gen.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func dialChannel(net string, ra Addr, dialer func(time.Time) (Conn, error), dead
1717
}
1818
timeout := deadline.Sub(time.Now())
1919
if timeout <= 0 {
20-
return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errTimeout}
20+
return nil, &OpError{Op: "dial", Net: net, Source: nil, Addr: ra, Err: errTimeout}
2121
}
2222
t := time.NewTimer(timeout)
2323
defer t.Stop()
@@ -33,7 +33,7 @@ func dialChannel(net string, ra Addr, dialer func(time.Time) (Conn, error), dead
3333
}()
3434
select {
3535
case <-t.C:
36-
return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errTimeout}
36+
return nil, &OpError{Op: "dial", Net: net, Source: nil, Addr: ra, Err: errTimeout}
3737
case racer := <-ch:
3838
return racer.Conn, racer.error
3939
}

src/net/error_test.go

+7-28
Original file line numberDiff line numberDiff line change
@@ -32,34 +32,13 @@ func (e *OpError) isValid() error {
3232
if e.Net == "" {
3333
return fmt.Errorf("OpError.Net is empty: %v", e)
3434
}
35-
switch addr := e.Addr.(type) {
36-
case *TCPAddr:
37-
if addr == nil {
38-
return fmt.Errorf("OpError.Addr is empty: %v", e)
39-
}
40-
case *UDPAddr:
41-
if addr == nil {
42-
return fmt.Errorf("OpError.Addr is empty: %v", e)
43-
}
44-
case *IPAddr:
45-
if addr == nil {
46-
return fmt.Errorf("OpError.Addr is empty: %v", e)
47-
}
48-
case *IPNet:
49-
if addr == nil {
50-
return fmt.Errorf("OpError.Addr is empty: %v", e)
51-
}
52-
case *UnixAddr:
53-
if addr == nil {
54-
return fmt.Errorf("OpError.Addr is empty: %v", e)
55-
}
56-
case *pipeAddr:
57-
if addr == nil {
58-
return fmt.Errorf("OpError.Addr is empty: %v", e)
59-
}
60-
case fileAddr:
61-
if addr == "" {
62-
return fmt.Errorf("OpError.Addr is empty: %v", e)
35+
for _, addr := range []Addr{e.Source, e.Addr} {
36+
if addr != nil {
37+
switch addr.(type) {
38+
case *TCPAddr, *UDPAddr, *IPAddr, *IPNet, *UnixAddr, *pipeAddr, fileAddr:
39+
default:
40+
return fmt.Errorf("OpError.Source or Addr is unknown type: %T, %v", addr, e)
41+
}
6342
}
6443
}
6544
if e.Err == nil {

src/net/file.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func (f fileAddr) String() string { return string(f) }
1818
func FileConn(f *os.File) (c Conn, err error) {
1919
c, err = fileConn(f)
2020
if err != nil {
21-
err = &OpError{Op: "file", Net: "file+net", Addr: fileAddr(f.Name()), Err: err}
21+
err = &OpError{Op: "file", Net: "file+net", Source: nil, Addr: fileAddr(f.Name()), Err: err}
2222
}
2323
return
2424
}
@@ -30,7 +30,7 @@ func FileConn(f *os.File) (c Conn, err error) {
3030
func FileListener(f *os.File) (ln Listener, err error) {
3131
ln, err = fileListener(f)
3232
if err != nil {
33-
err = &OpError{Op: "file", Net: "file+net", Addr: fileAddr(f.Name()), Err: err}
33+
err = &OpError{Op: "file", Net: "file+net", Source: nil, Addr: fileAddr(f.Name()), Err: err}
3434
}
3535
return
3636
}
@@ -42,7 +42,7 @@ func FileListener(f *os.File) (ln Listener, err error) {
4242
func FilePacketConn(f *os.File) (c PacketConn, err error) {
4343
c, err = filePacketConn(f)
4444
if err != nil {
45-
err = &OpError{Op: "file", Net: "file+net", Addr: fileAddr(f.Name()), Err: err}
45+
err = &OpError{Op: "file", Net: "file+net", Source: nil, Addr: fileAddr(f.Name()), Err: err}
4646
}
4747
return
4848
}

src/net/interface.go

+12-12
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,11 @@ func (f Flags) String() string {
6262
// Addrs returns interface addresses for a specific interface.
6363
func (ifi *Interface) Addrs() ([]Addr, error) {
6464
if ifi == nil {
65-
return nil, &OpError{Op: "route", Net: "ip+net", Addr: nil, Err: errInvalidInterface}
65+
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
6666
}
6767
ifat, err := interfaceAddrTable(ifi)
6868
if err != nil {
69-
err = &OpError{Op: "route", Net: "ip+net", Addr: nil, Err: err}
69+
err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
7070
}
7171
return ifat, err
7272
}
@@ -75,11 +75,11 @@ func (ifi *Interface) Addrs() ([]Addr, error) {
7575
// a specific interface.
7676
func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
7777
if ifi == nil {
78-
return nil, &OpError{Op: "route", Net: "ip+net", Addr: nil, Err: errInvalidInterface}
78+
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
7979
}
8080
ifat, err := interfaceMulticastAddrTable(ifi)
8181
if err != nil {
82-
err = &OpError{Op: "route", Net: "ip+net", Addr: nil, Err: err}
82+
err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
8383
}
8484
return ifat, err
8585
}
@@ -88,7 +88,7 @@ func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
8888
func Interfaces() ([]Interface, error) {
8989
ift, err := interfaceTable(0)
9090
if err != nil {
91-
err = &OpError{Op: "route", Net: "ip+net", Addr: nil, Err: err}
91+
err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
9292
}
9393
return ift, err
9494
}
@@ -98,23 +98,23 @@ func Interfaces() ([]Interface, error) {
9898
func InterfaceAddrs() ([]Addr, error) {
9999
ifat, err := interfaceAddrTable(nil)
100100
if err != nil {
101-
err = &OpError{Op: "route", Net: "ip+net", Addr: nil, Err: err}
101+
err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
102102
}
103103
return ifat, err
104104
}
105105

106106
// InterfaceByIndex returns the interface specified by index.
107107
func InterfaceByIndex(index int) (*Interface, error) {
108108
if index <= 0 {
109-
return nil, &OpError{Op: "route", Net: "ip+net", Addr: nil, Err: errInvalidInterfaceIndex}
109+
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex}
110110
}
111111
ift, err := interfaceTable(index)
112112
if err != nil {
113-
return nil, &OpError{Op: "route", Net: "ip+net", Addr: nil, Err: err}
113+
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
114114
}
115115
ifi, err := interfaceByIndex(ift, index)
116116
if err != nil {
117-
err = &OpError{Op: "route", Net: "ip+net", Addr: nil, Err: err}
117+
err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
118118
}
119119
return ifi, err
120120
}
@@ -131,16 +131,16 @@ func interfaceByIndex(ift []Interface, index int) (*Interface, error) {
131131
// InterfaceByName returns the interface specified by name.
132132
func InterfaceByName(name string) (*Interface, error) {
133133
if name == "" {
134-
return nil, &OpError{Op: "route", Net: "ip+net", Addr: nil, Err: errInvalidInterfaceName}
134+
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceName}
135135
}
136136
ift, err := interfaceTable(0)
137137
if err != nil {
138-
return nil, &OpError{Op: "route", Net: "ip+net", Addr: nil, Err: err}
138+
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
139139
}
140140
for _, ifi := range ift {
141141
if name == ifi.Name {
142142
return &ifi, nil
143143
}
144144
}
145-
return nil, &OpError{Op: "route", Net: "ip+net", Addr: nil, Err: errNoSuchInterface}
145+
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface}
146146
}

src/net/iprawsock_plan9.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,20 @@ type IPConn struct {
2323
// Timeout() == true after a fixed time limit; see SetDeadline and
2424
// SetReadDeadline.
2525
func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
26-
return 0, nil, &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: syscall.EPLAN9}
26+
return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
2727
}
2828

2929
// ReadFrom implements the PacketConn ReadFrom method.
3030
func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
31-
return 0, nil, &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: syscall.EPLAN9}
31+
return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
3232
}
3333

3434
// ReadMsgIP reads a packet from c, copying the payload into b and the
3535
// associated out-of-band data into oob. It returns the number of
3636
// bytes copied into b, the number of bytes copied into oob, the flags
3737
// that were set on the packet and the source address of the packet.
3838
func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
39-
return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.net, Addr: c.fd.laddr, Err: syscall.EPLAN9}
39+
return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
4040
}
4141

4242
// WriteToIP writes an IP packet to addr via c, copying the payload
@@ -47,19 +47,19 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err
4747
// SetWriteDeadline. On packet-oriented connections, write timeouts
4848
// are rare.
4949
func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
50-
return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: syscall.EPLAN9}
50+
return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
5151
}
5252

5353
// WriteTo implements the PacketConn WriteTo method.
5454
func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
55-
return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: syscall.EPLAN9}
55+
return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
5656
}
5757

5858
// WriteMsgIP writes a packet to addr via c, copying the payload from
5959
// b and the associated out-of-band data from oob. It returns the
6060
// number of payload and out-of-band bytes written.
6161
func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
62-
return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: syscall.EPLAN9}
62+
return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
6363
}
6464

6565
// DialIP connects to the remote address raddr on the network protocol
@@ -70,13 +70,13 @@ func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
7070
}
7171

7272
func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
73-
return nil, syscall.EPLAN9
73+
return nil, &OpError{Op: "dial", Net: netProto, Source: laddr, Addr: raddr, Err: syscall.EPLAN9}
7474
}
7575

7676
// ListenIP listens for incoming IP packets addressed to the local
7777
// address laddr. The returned connection's ReadFrom and WriteTo
7878
// methods can be used to receive and send IP packets with per-packet
7979
// addressing.
8080
func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
81-
return nil, syscall.EPLAN9
81+
return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr, Err: syscall.EPLAN9}
8282
}

0 commit comments

Comments
 (0)