net: use original raddr if getpeername fails

This CL updates CL 7511043;
- adds new test cases for both UDPConn and UnixConn,
- makes sure unnamed UnixAddr handling,
- replaces t.Errorf with t.Fatalf in sockname related test cases.

Fixes #3721 (again).
Fixes #3838 (again).

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7627048
diff --git a/src/pkg/net/server_test.go b/src/pkg/net/server_test.go
index c101ffe..9194a8e 100644
--- a/src/pkg/net/server_test.go
+++ b/src/pkg/net/server_test.go
@@ -402,7 +402,7 @@
 			t.Fatalf("Dial(%q, %q) failed: %v", net, taddr, err)
 		}
 	case "unixgram":
-		c, err = DialUnix(net, &UnixAddr{laddr, net}, &UnixAddr{taddr, net})
+		c, err = DialUnix(net, &UnixAddr{Name: laddr, Net: net}, &UnixAddr{Name: taddr, Net: net})
 		if err != nil {
 			t.Fatalf("DialUnix(%q, {%q, %q}) failed: %v", net, laddr, taddr, err)
 		}
diff --git a/src/pkg/net/sock_posix.go b/src/pkg/net/sock_posix.go
index 2ebde87..c8a94f5 100644
--- a/src/pkg/net/sock_posix.go
+++ b/src/pkg/net/sock_posix.go
@@ -65,10 +65,10 @@
 	lsa, _ := syscall.Getsockname(s)
 	laddr := toAddr(lsa)
 	rsa, _ := syscall.Getpeername(s)
+	if rsa == nil {
+		rsa = ursa
+	}
 	raddr := toAddr(rsa)
 	fd.setAddr(laddr, raddr)
-	if fd.raddr == nil {
-		fd.raddr = toAddr(ursa)
-	}
 	return fd, nil
 }
diff --git a/src/pkg/net/tcp_test.go b/src/pkg/net/tcp_test.go
index add8e48..b89202f 100644
--- a/src/pkg/net/tcp_test.go
+++ b/src/pkg/net/tcp_test.go
@@ -217,14 +217,12 @@
 	for _, tt := range tcpListenerNameTests {
 		ln, err := ListenTCP(tt.net, tt.laddr)
 		if err != nil {
-			t.Errorf("ListenTCP failed: %v", err)
-			return
+			t.Fatalf("ListenTCP failed: %v", err)
 		}
 		defer ln.Close()
 		la := ln.Addr()
 		if a, ok := la.(*TCPAddr); !ok || a.Port == 0 {
-			t.Errorf("got %v; expected a proper address with non-zero port number", la)
-			return
+			t.Fatalf("got %v; expected a proper address with non-zero port number", la)
 		}
 	}
 }
diff --git a/src/pkg/net/udp_test.go b/src/pkg/net/udp_test.go
index b3cafb0..7a64c19 100644
--- a/src/pkg/net/udp_test.go
+++ b/src/pkg/net/udp_test.go
@@ -159,14 +159,50 @@
 	for _, tt := range udpConnLocalNameTests {
 		c, err := ListenUDP(tt.net, tt.laddr)
 		if err != nil {
-			t.Errorf("ListenUDP failed: %v", err)
-			return
+			t.Fatalf("ListenUDP failed: %v", err)
 		}
 		defer c.Close()
 		la := c.LocalAddr()
 		if a, ok := la.(*UDPAddr); !ok || a.Port == 0 {
-			t.Errorf("got %v; expected a proper address with non-zero port number", la)
-			return
+			t.Fatalf("got %v; expected a proper address with non-zero port number", la)
+		}
+	}
+}
+
+func TestUDPConnLocalAndRemoteNames(t *testing.T) {
+	for _, laddr := range []string{"", "127.0.0.1:0"} {
+		c1, err := ListenPacket("udp", "127.0.0.1:0")
+		if err != nil {
+			t.Fatalf("ListenUDP failed: %v", err)
+		}
+		defer c1.Close()
+
+		var la *UDPAddr
+		if laddr != "" {
+			var err error
+			if la, err = ResolveUDPAddr("udp", laddr); err != nil {
+				t.Fatalf("ResolveUDPAddr failed: %v", err)
+			}
+		}
+		c2, err := DialUDP("udp", la, c1.LocalAddr().(*UDPAddr))
+		if err != nil {
+			t.Fatalf("DialUDP failed: %v", err)
+		}
+		defer c2.Close()
+
+		var connAddrs = [4]struct {
+			got Addr
+			ok  bool
+		}{
+			{c1.LocalAddr(), true},
+			{c1.(*UDPConn).RemoteAddr(), false},
+			{c2.LocalAddr(), true},
+			{c2.RemoteAddr(), true},
+		}
+		for _, ca := range connAddrs {
+			if a, ok := ca.got.(*UDPAddr); ok != ca.ok || ok && a.Port == 0 {
+				t.Fatalf("got %v; expected a proper address with non-zero port number", ca.got)
+			}
 		}
 	}
 }
diff --git a/src/pkg/net/unix_test.go b/src/pkg/net/unix_test.go
index 2eaabe8..5e63e9d 100644
--- a/src/pkg/net/unix_test.go
+++ b/src/pkg/net/unix_test.go
@@ -33,7 +33,6 @@
 
 	off := make(chan bool)
 	data := [5]byte{1, 2, 3, 4, 5}
-
 	go func() {
 		defer func() { off <- true }()
 		s, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0)
@@ -54,15 +53,13 @@
 	c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
 	n, from, err := c.ReadFrom(b)
 	if err != nil {
-		t.Errorf("UnixConn.ReadFrom failed: %v", err)
-		return
+		t.Fatalf("UnixConn.ReadFrom failed: %v", err)
 	}
 	if from != nil {
-		t.Errorf("neighbor address is %v", from)
+		t.Fatalf("neighbor address is %v", from)
 	}
 	if !bytes.Equal(b[:n], data[:]) {
-		t.Errorf("got %v, want %v", b[:n], data[:])
-		return
+		t.Fatalf("got %v, want %v", b[:n], data[:])
 	}
 }
 
@@ -101,13 +98,12 @@
 
 	<-off
 	c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
-	var peer Addr
-	if _, peer, err = c.ReadFrom(nil); err != nil {
-		t.Errorf("UnixConn.ReadFrom failed: %v", err)
-		return
+	_, from, err := c.ReadFrom(nil)
+	if err != nil {
+		t.Fatalf("UnixConn.ReadFrom failed: %v", err)
 	}
-	if peer != nil {
-		t.Errorf("peer adddress is %v", peer)
+	if from != nil {
+		t.Fatalf("neighbor address is %v", from)
 	}
 }
 
@@ -126,10 +122,10 @@
 	// retrieve the autobind address
 	autoAddr := c1.LocalAddr().(*UnixAddr)
 	if len(autoAddr.Name) <= 1 {
-		t.Fatalf("Invalid autobind address: %v", autoAddr)
+		t.Fatalf("invalid autobind address: %v", autoAddr)
 	}
 	if autoAddr.Name[0] != '@' {
-		t.Fatalf("Invalid autobind address: %v", autoAddr)
+		t.Fatalf("invalid autobind address: %v", autoAddr)
 	}
 
 	c2, err := DialUnix("unixgram", nil, autoAddr)
@@ -139,6 +135,112 @@
 	defer c2.Close()
 
 	if !reflect.DeepEqual(c1.LocalAddr(), c2.RemoteAddr()) {
-		t.Fatalf("Expected autobind address %v, got %v", c1.LocalAddr(), c2.RemoteAddr())
+		t.Fatalf("expected autobind address %v, got %v", c1.LocalAddr(), c2.RemoteAddr())
+	}
+}
+
+func TestUnixConnLocalAndRemoteNames(t *testing.T) {
+	for _, laddr := range []string{"", testUnixAddr()} {
+		taddr := testUnixAddr()
+		ta, err := ResolveUnixAddr("unix", taddr)
+		if err != nil {
+			t.Fatalf("ResolveUnixAddr failed: %v", err)
+		}
+		ln, err := ListenUnix("unix", ta)
+		if err != nil {
+			t.Fatalf("ListenUnix failed: %v", err)
+		}
+		defer func() {
+			ln.Close()
+			os.Remove(taddr)
+		}()
+
+		done := make(chan int)
+		go transponder(t, ln, done)
+
+		la, err := ResolveUnixAddr("unix", laddr)
+		if err != nil {
+			t.Fatalf("ResolveUnixAddr failed: %v", err)
+		}
+		c, err := DialUnix("unix", la, ta)
+		if err != nil {
+			t.Fatalf("DialUnix failed: %v", err)
+		}
+		defer func() {
+			c.Close()
+			if la != nil {
+				defer os.Remove(laddr)
+			}
+		}()
+		if _, err := c.Write([]byte("UNIXCONN LOCAL AND REMOTE NAME TEST")); err != nil {
+			t.Fatalf("UnixConn.Write failed: %v", err)
+		}
+
+		if runtime.GOOS == "linux" && laddr == "" {
+			laddr = "@" // autobind feature
+		}
+		var connAddrs = [3]struct{ got, want Addr }{
+			{ln.Addr(), ta},
+			{c.LocalAddr(), &UnixAddr{Name: laddr, Net: "unix"}},
+			{c.RemoteAddr(), ta},
+		}
+		for _, ca := range connAddrs {
+			if !reflect.DeepEqual(ca.got, ca.want) {
+				t.Fatalf("got %#v, expected %#v", ca.got, ca.want)
+			}
+		}
+
+		<-done
+	}
+}
+
+func TestUnixgramConnLocalAndRemoteNames(t *testing.T) {
+	for _, laddr := range []string{"", testUnixAddr()} {
+		taddr := testUnixAddr()
+		ta, err := ResolveUnixAddr("unixgram", taddr)
+		if err != nil {
+			t.Fatalf("ResolveUnixAddr failed: %v", err)
+		}
+		c1, err := ListenUnixgram("unixgram", ta)
+		if err != nil {
+			t.Fatalf("ListenUnixgram failed: %v", err)
+		}
+		defer func() {
+			c1.Close()
+			os.Remove(taddr)
+		}()
+
+		var la *UnixAddr
+		if laddr != "" {
+			var err error
+			if la, err = ResolveUnixAddr("unixgram", laddr); err != nil {
+				t.Fatalf("ResolveUnixAddr failed: %v", err)
+			}
+		}
+		c2, err := DialUnix("unixgram", la, ta)
+		if err != nil {
+			t.Fatalf("DialUnix failed: %v", err)
+		}
+		defer func() {
+			c2.Close()
+			if la != nil {
+				defer os.Remove(laddr)
+			}
+		}()
+
+		if runtime.GOOS == "linux" && laddr == "" {
+			laddr = "@" // autobind feature
+		}
+		var connAddrs = [4]struct{ got, want Addr }{
+			{c1.LocalAddr(), ta},
+			{c1.RemoteAddr(), nil},
+			{c2.LocalAddr(), &UnixAddr{Name: laddr, Net: "unixgram"}},
+			{c2.RemoteAddr(), ta},
+		}
+		for _, ca := range connAddrs {
+			if !reflect.DeepEqual(ca.got, ca.want) {
+				t.Fatalf("got %#v, expected %#v", ca.got, ca.want)
+			}
+		}
 	}
 }
diff --git a/src/pkg/net/unixsock_posix.go b/src/pkg/net/unixsock_posix.go
index 8d57dac..abdff09 100644
--- a/src/pkg/net/unixsock_posix.go
+++ b/src/pkg/net/unixsock_posix.go
@@ -15,6 +15,13 @@
 	"time"
 )
 
+func (a *UnixAddr) isUnnamed() bool {
+	if a == nil || a.Name == "" {
+		return true
+	}
+	return false
+}
+
 func unixSocket(net string, laddr, raddr *UnixAddr, mode string, deadline time.Time) (*netFD, error) {
 	var sotype int
 	switch net {
@@ -31,12 +38,12 @@
 	var la, ra syscall.Sockaddr
 	switch mode {
 	case "dial":
-		if laddr != nil {
+		if !laddr.isUnnamed() {
 			la = &syscall.SockaddrUnix{Name: laddr.Name}
 		}
 		if raddr != nil {
 			ra = &syscall.SockaddrUnix{Name: raddr.Name}
-		} else if sotype != syscall.SOCK_DGRAM || laddr == nil {
+		} else if sotype != syscall.SOCK_DGRAM || laddr.isUnnamed() {
 			return nil, &OpError{Op: mode, Net: net, Err: errMissingAddress}
 		}
 	case "listen":
@@ -69,21 +76,21 @@
 
 func sockaddrToUnix(sa syscall.Sockaddr) Addr {
 	if s, ok := sa.(*syscall.SockaddrUnix); ok {
-		return &UnixAddr{s.Name, "unix"}
+		return &UnixAddr{Name: s.Name, Net: "unix"}
 	}
 	return nil
 }
 
 func sockaddrToUnixgram(sa syscall.Sockaddr) Addr {
 	if s, ok := sa.(*syscall.SockaddrUnix); ok {
-		return &UnixAddr{s.Name, "unixgram"}
+		return &UnixAddr{Name: s.Name, Net: "unixgram"}
 	}
 	return nil
 }
 
 func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr {
 	if s, ok := sa.(*syscall.SockaddrUnix); ok {
-		return &UnixAddr{s.Name, "unixpacket"}
+		return &UnixAddr{Name: s.Name, Net: "unixpacket"}
 	}
 	return nil
 }
@@ -92,10 +99,10 @@
 	switch sotype {
 	case syscall.SOCK_STREAM:
 		return "unix"
-	case syscall.SOCK_SEQPACKET:
-		return "unixpacket"
 	case syscall.SOCK_DGRAM:
 		return "unixgram"
+	case syscall.SOCK_SEQPACKET:
+		return "unixpacket"
 	default:
 		panic("sotypeToNet unknown socket type")
 	}
@@ -124,7 +131,7 @@
 	switch sa := sa.(type) {
 	case *syscall.SockaddrUnix:
 		if sa.Name != "" {
-			addr = &UnixAddr{sa.Name, sotypeToNet(c.fd.sotype)}
+			addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
 		}
 	}
 	return
@@ -151,7 +158,7 @@
 	switch sa := sa.(type) {
 	case *syscall.SockaddrUnix:
 		if sa.Name != "" {
-			addr = &UnixAddr{sa.Name, sotypeToNet(c.fd.sotype)}
+			addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
 		}
 	}
 	return