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 <iant@golang.org>
diff --git a/src/net/net.go b/src/net/net.go
index 41fc081..955d018 100644
--- a/src/net/net.go
+++ b/src/net/net.go
@@ -123,12 +123,7 @@
 	}
 	n, err := c.fd.Read(b)
 	if err != nil && err != io.EOF {
-		err = &OpError{Op: "read", Net: c.fd.net, Err: err}
-		if c.fd.raddr != nil {
-			err.(*OpError).Addr = c.fd.raddr
-		} else {
-			err.(*OpError).Addr = c.fd.laddr // for unconnected-mode sockets
-		}
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
 	}
 	return n, err
 }
@@ -140,12 +135,7 @@
 	}
 	n, err := c.fd.Write(b)
 	if err != nil {
-		err = &OpError{Op: "write", Net: c.fd.net, Err: err}
-		if c.fd.raddr != nil {
-			err.(*OpError).Addr = c.fd.raddr
-		} else {
-			err.(*OpError).Addr = c.fd.laddr // for unconnected-mode sockets
-		}
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
 	}
 	return n, err
 }
@@ -157,12 +147,7 @@
 	}
 	err := c.fd.Close()
 	if err != nil {
-		err = &OpError{Op: "close", Net: c.fd.net, Err: err}
-		if c.fd.raddr != nil {
-			err.(*OpError).Addr = c.fd.raddr
-		} else {
-			err.(*OpError).Addr = c.fd.laddr // for unconnected-mode sockets
-		}
+		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
 	}
 	return err
 }
@@ -193,7 +178,7 @@
 		return syscall.EINVAL
 	}
 	if err := c.fd.setDeadline(t); err != nil {
-		return &OpError{Op: "set", Net: c.fd.net, Addr: c.fd.laddr, Err: err}
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
 	}
 	return nil
 }
@@ -204,7 +189,7 @@
 		return syscall.EINVAL
 	}
 	if err := c.fd.setReadDeadline(t); err != nil {
-		return &OpError{Op: "set", Net: c.fd.net, Addr: c.fd.laddr, Err: err}
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
 	}
 	return nil
 }
@@ -215,7 +200,7 @@
 		return syscall.EINVAL
 	}
 	if err := c.fd.setWriteDeadline(t); err != nil {
-		return &OpError{Op: "set", Net: c.fd.net, Addr: c.fd.laddr, Err: err}
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
 	}
 	return nil
 }
@@ -227,7 +212,7 @@
 		return syscall.EINVAL
 	}
 	if err := setReadBuffer(c.fd, bytes); err != nil {
-		return &OpError{Op: "set", Net: c.fd.net, Addr: c.fd.laddr, Err: err}
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
 	}
 	return nil
 }
@@ -239,7 +224,7 @@
 		return syscall.EINVAL
 	}
 	if err := setWriteBuffer(c.fd, bytes); err != nil {
-		return &OpError{Op: "set", Net: c.fd.net, Addr: c.fd.laddr, Err: err}
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
 	}
 	return nil
 }
@@ -254,7 +239,7 @@
 func (c *conn) File() (f *os.File, err error) {
 	f, err = c.fd.dup()
 	if err != nil {
-		err = &OpError{Op: "file", Net: c.fd.net, Addr: c.fd.laddr, Err: err}
+		err = &OpError{Op: "file", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
 	}
 	return
 }
@@ -352,7 +337,17 @@
 	// such as "tcp" or "udp6".
 	Net string
 
-	// Addr is the network address on which this error occurred.
+	// For operations involving a remote network connection, like
+	// Dial, Read, or Write, Source is the corresponding local
+	// network address.
+	Source Addr
+
+	// Addr is the network address for which this error occurred.
+	// For local operations, like Listen or SetDeadline, Addr is
+	// the address of the local endpoint being manipulated.
+	// For operations involving a remote network connection, like
+	// Dial, Read, or Write, Addr is the remote address of that
+	// connection.
 	Addr Addr
 
 	// Err is the error that occurred during the operation.
@@ -367,8 +362,16 @@
 	if e.Net != "" {
 		s += " " + e.Net
 	}
+	if e.Source != nil {
+		s += " " + e.Source.String()
+	}
 	if e.Addr != nil {
-		s += " " + e.Addr.String()
+		if e.Source != nil {
+			s += "->"
+		} else {
+			s += " "
+		}
+		s += e.Addr.String()
 	}
 	s += ": " + e.Err.Error()
 	return s