ipv4,ipv6: retry ENOBUFS and shut down the PacketConn on failure in TestPacketConnConcurrentReadWriteUnicastUDP

This ports CL 376094 and CL 376095 to the UDP variants of the test.

Fixes golang/go#52549 (hopefully).

Change-Id: I2537af1bc14a42b2e51882e5d646912e1239758c
Reviewed-on: https://go-review.googlesource.com/c/net/+/402059
Run-TryBot: Bryan Mills <bcmills@google.com>
Auto-Submit: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
diff --git a/ipv4/readwrite_test.go b/ipv4/readwrite_test.go
index 11281a4..27aaa7b 100644
--- a/ipv4/readwrite_test.go
+++ b/ipv4/readwrite_test.go
@@ -244,16 +244,31 @@
 		t.Fatal(err)
 	}
 
+	var firstError sync.Once
+	fatalf := func(format string, args ...interface{}) {
+		// On the first error, close the PacketConn to unblock the remaining
+		// goroutines. Suppress any further errors, which may occur simply due to
+		// closing the PacketConn.
+		first := false
+		firstError.Do(func() {
+			first = true
+			p.Close()
+		})
+		if first {
+			t.Helper()
+			t.Errorf(format, args...)
+		}
+		runtime.Goexit()
+	}
+
 	var wg sync.WaitGroup
 	reader := func() {
 		defer wg.Done()
 		rb := make([]byte, 128)
 		if n, cm, _, err := p.ReadFrom(rb); err != nil {
-			t.Error(err)
-			return
+			fatalf("%v", err)
 		} else if !bytes.Equal(rb[:n], wb) {
-			t.Errorf("got %v; want %v", rb[:n], wb)
-			return
+			fatalf("got %v; want %v", rb[:n], wb)
 		} else {
 			s := cm.String()
 			if strings.Contains(s, ",") {
@@ -270,15 +285,24 @@
 			cm.IfIndex = ifi.Index
 		}
 		if err := p.SetControlMessage(cf, toggle); err != nil {
-			t.Error(err)
-			return
+			fatalf("%v", err)
 		}
-		if n, err := p.WriteTo(wb, &cm, dst); err != nil {
-			t.Error(err)
-			return
-		} else if n != len(wb) {
-			t.Errorf("got %d; want %d", n, len(wb))
-			return
+
+		backoff := time.Millisecond
+		for {
+			n, err := p.WriteTo(wb, &cm, dst)
+			if err != nil {
+				if n == 0 && isENOBUFS(err) {
+					time.Sleep(backoff)
+					backoff *= 2
+					continue
+				}
+				fatalf("%v", err)
+			}
+			if n != len(wb) {
+				fatalf("got %d; want %d", n, len(wb))
+			}
+			break
 		}
 	}
 
diff --git a/ipv6/readwrite_test.go b/ipv6/readwrite_test.go
index d319632..e8db119 100644
--- a/ipv6/readwrite_test.go
+++ b/ipv6/readwrite_test.go
@@ -247,16 +247,31 @@
 		t.Fatal(err)
 	}
 
+	var firstError sync.Once
+	fatalf := func(format string, args ...interface{}) {
+		// On the first error, close the PacketConn to unblock the remaining
+		// goroutines. Suppress any further errors, which may occur simply due to
+		// closing the PacketConn.
+		first := false
+		firstError.Do(func() {
+			first = true
+			p.Close()
+		})
+		if first {
+			t.Helper()
+			t.Errorf(format, args...)
+		}
+		runtime.Goexit()
+	}
+
 	var wg sync.WaitGroup
 	reader := func() {
 		defer wg.Done()
 		rb := make([]byte, 128)
 		if n, cm, _, err := p.ReadFrom(rb); err != nil {
-			t.Error(err)
-			return
+			fatalf("%v", err)
 		} else if !bytes.Equal(rb[:n], wb) {
-			t.Errorf("got %v; want %v", rb[:n], wb)
-			return
+			fatalf("got %v; want %v", rb[:n], wb)
 		} else {
 			s := cm.String()
 			if strings.Contains(s, ",") {
@@ -274,15 +289,24 @@
 			cm.IfIndex = ifi.Index
 		}
 		if err := p.SetControlMessage(cf, toggle); err != nil {
-			t.Error(err)
-			return
+			fatalf("%v", err)
 		}
-		if n, err := p.WriteTo(wb, &cm, dst); err != nil {
-			t.Error(err)
-			return
-		} else if n != len(wb) {
-			t.Errorf("got %d; want %d", n, len(wb))
-			return
+
+		backoff := time.Millisecond
+		for {
+			n, err := p.WriteTo(wb, &cm, dst)
+			if err != nil {
+				if n == 0 && isENOBUFS(err) {
+					time.Sleep(backoff)
+					backoff *= 2
+					continue
+				}
+				fatalf("%v", err)
+			}
+			if n != len(wb) {
+				fatalf("got %d; want %d", n, len(wb))
+			}
+			break
 		}
 	}