Source file src/net/udpsock_test.go

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package net
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"internal/asan"
    11  	"internal/race"
    12  	"internal/testenv"
    13  	"net/netip"
    14  	"os"
    15  	"reflect"
    16  	"runtime"
    17  	"testing"
    18  	"time"
    19  )
    20  
    21  func BenchmarkUDP6LinkLocalUnicast(b *testing.B) {
    22  	testHookUninstaller.Do(uninstallTestHooks)
    23  
    24  	if !supportsIPv6() {
    25  		b.Skip("IPv6 is not supported")
    26  	}
    27  	ifi := loopbackInterface()
    28  	if ifi == nil {
    29  		b.Skip("loopback interface not found")
    30  	}
    31  	lla := ipv6LinkLocalUnicastAddr(ifi)
    32  	if lla == "" {
    33  		b.Skip("IPv6 link-local unicast address not found")
    34  	}
    35  
    36  	c1, err := ListenPacket("udp6", JoinHostPort(lla+"%"+ifi.Name, "0"))
    37  	if err != nil {
    38  		b.Fatal(err)
    39  	}
    40  	defer c1.Close()
    41  	c2, err := ListenPacket("udp6", JoinHostPort(lla+"%"+ifi.Name, "0"))
    42  	if err != nil {
    43  		b.Fatal(err)
    44  	}
    45  	defer c2.Close()
    46  
    47  	var buf [1]byte
    48  	for i := 0; i < b.N; i++ {
    49  		if _, err := c1.WriteTo(buf[:], c2.LocalAddr()); err != nil {
    50  			b.Fatal(err)
    51  		}
    52  		if _, _, err := c2.ReadFrom(buf[:]); err != nil {
    53  			b.Fatal(err)
    54  		}
    55  	}
    56  }
    57  
    58  type resolveUDPAddrTest struct {
    59  	network       string
    60  	litAddrOrName string
    61  	addr          *UDPAddr
    62  	err           error
    63  }
    64  
    65  var resolveUDPAddrTests = []resolveUDPAddrTest{
    66  	{"udp", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
    67  	{"udp4", "127.0.0.1:65535", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
    68  
    69  	{"udp", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},
    70  	{"udp6", "[::1]:65535", &UDPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
    71  
    72  	{"udp", "[::1%en0]:1", &UDPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
    73  	{"udp6", "[::1%911]:2", &UDPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
    74  
    75  	{"", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
    76  	{"", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},         // Go 1.0 behavior
    77  
    78  	{"udp", ":12345", &UDPAddr{Port: 12345}, nil},
    79  
    80  	{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
    81  
    82  	{"udp", "127.0.0.1:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
    83  	{"udp", "[::ffff:127.0.0.1]:domain", &UDPAddr{IP: ParseIP("::ffff:127.0.0.1"), Port: 53}, nil},
    84  	{"udp", "[2001:db8::1]:domain", &UDPAddr{IP: ParseIP("2001:db8::1"), Port: 53}, nil},
    85  	{"udp4", "127.0.0.1:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
    86  	{"udp4", "[::ffff:127.0.0.1]:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
    87  	{"udp6", "[2001:db8::1]:domain", &UDPAddr{IP: ParseIP("2001:db8::1"), Port: 53}, nil},
    88  
    89  	{"udp4", "[2001:db8::1]:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "2001:db8::1"}},
    90  	{"udp6", "127.0.0.1:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "127.0.0.1"}},
    91  	{"udp6", "[::ffff:127.0.0.1]:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "::ffff:127.0.0.1"}},
    92  }
    93  
    94  func TestResolveUDPAddr(t *testing.T) {
    95  	origTestHookLookupIP := testHookLookupIP
    96  	defer func() { testHookLookupIP = origTestHookLookupIP }()
    97  	testHookLookupIP = lookupLocalhost
    98  
    99  	for _, tt := range resolveUDPAddrTests {
   100  		addr, err := ResolveUDPAddr(tt.network, tt.litAddrOrName)
   101  		if !reflect.DeepEqual(addr, tt.addr) || !reflect.DeepEqual(err, tt.err) {
   102  			t.Errorf("ResolveUDPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr, err, tt.addr, tt.err)
   103  			continue
   104  		}
   105  		if err == nil {
   106  			addr2, err := ResolveUDPAddr(addr.Network(), addr.String())
   107  			if !reflect.DeepEqual(addr2, tt.addr) || err != tt.err {
   108  				t.Errorf("(%q, %q): ResolveUDPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr.Network(), addr.String(), addr2, err, tt.addr, tt.err)
   109  			}
   110  		}
   111  	}
   112  }
   113  
   114  func TestWriteToUDP(t *testing.T) {
   115  	switch runtime.GOOS {
   116  	case "plan9":
   117  		t.Skipf("not supported on %s", runtime.GOOS)
   118  	}
   119  
   120  	if !testableNetwork("udp") {
   121  		t.Skipf("skipping: udp not supported")
   122  	}
   123  
   124  	c, err := ListenPacket("udp", "127.0.0.1:0")
   125  	if err != nil {
   126  		t.Fatal(err)
   127  	}
   128  	defer c.Close()
   129  
   130  	testWriteToConn(t, c.LocalAddr().String())
   131  	testWriteToPacketConn(t, c.LocalAddr().String())
   132  }
   133  
   134  func testWriteToConn(t *testing.T, raddr string) {
   135  	c, err := Dial("udp", raddr)
   136  	if err != nil {
   137  		t.Fatal(err)
   138  	}
   139  	defer c.Close()
   140  
   141  	ra, err := ResolveUDPAddr("udp", raddr)
   142  	if err != nil {
   143  		t.Fatal(err)
   144  	}
   145  	rap := ra.AddrPort()
   146  
   147  	assertErrWriteToConnected := func(t *testing.T, err error) {
   148  		t.Helper()
   149  		if e, ok := err.(*OpError); !ok || e.Err != ErrWriteToConnected {
   150  			t.Errorf("got %v; want ErrWriteToConnected", err)
   151  		}
   152  	}
   153  
   154  	b := []byte("CONNECTED-MODE SOCKET")
   155  	_, err = c.(*UDPConn).WriteToUDPAddrPort(b, rap)
   156  	assertErrWriteToConnected(t, err)
   157  	_, err = c.(*UDPConn).WriteToUDP(b, ra)
   158  	assertErrWriteToConnected(t, err)
   159  	_, err = c.(*UDPConn).WriteTo(b, ra)
   160  	assertErrWriteToConnected(t, err)
   161  	_, err = c.Write(b)
   162  	if err != nil {
   163  		t.Errorf("c.Write(b) = %v; want nil", err)
   164  	}
   165  	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra)
   166  	assertErrWriteToConnected(t, err)
   167  	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
   168  	if err != nil {
   169  		t.Errorf("c.WriteMsgUDP(b, nil, nil) = %v; want nil", err)
   170  	}
   171  	_, _, err = c.(*UDPConn).WriteMsgUDPAddrPort(b, nil, rap)
   172  	assertErrWriteToConnected(t, err)
   173  	_, _, err = c.(*UDPConn).WriteMsgUDPAddrPort(b, nil, netip.AddrPort{})
   174  	if err != nil {
   175  		t.Errorf("c.WriteMsgUDPAddrPort(b, nil, netip.AddrPort{}) = %v; want nil", err)
   176  	}
   177  }
   178  
   179  func testWriteToPacketConn(t *testing.T, raddr string) {
   180  	c, err := ListenPacket("udp", "127.0.0.1:0")
   181  	if err != nil {
   182  		t.Fatal(err)
   183  	}
   184  	defer c.Close()
   185  
   186  	ra, err := ResolveUDPAddr("udp", raddr)
   187  	if err != nil {
   188  		t.Fatal(err)
   189  	}
   190  
   191  	b := []byte("UNCONNECTED-MODE SOCKET")
   192  	_, err = c.(*UDPConn).WriteToUDP(b, ra)
   193  	if err != nil {
   194  		t.Fatal(err)
   195  	}
   196  	_, err = c.WriteTo(b, ra)
   197  	if err != nil {
   198  		t.Fatal(err)
   199  	}
   200  	_, err = c.(*UDPConn).Write(b)
   201  	if err == nil {
   202  		t.Fatal("should fail")
   203  	}
   204  	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
   205  	if err == nil {
   206  		t.Fatal("should fail")
   207  	}
   208  	if err != nil && err.(*OpError).Err != errMissingAddress {
   209  		t.Fatalf("should fail as errMissingAddress: %v", err)
   210  	}
   211  	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra)
   212  	if err != nil {
   213  		t.Fatal(err)
   214  	}
   215  }
   216  
   217  var udpConnLocalNameTests = []struct {
   218  	net   string
   219  	laddr *UDPAddr
   220  }{
   221  	{"udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)}},
   222  	{"udp4", &UDPAddr{}},
   223  	{"udp4", nil},
   224  }
   225  
   226  func TestUDPConnLocalName(t *testing.T) {
   227  	testenv.MustHaveExternalNetwork(t)
   228  
   229  	for _, tt := range udpConnLocalNameTests {
   230  		t.Run(fmt.Sprint(tt.laddr), func(t *testing.T) {
   231  			if !testableNetwork(tt.net) {
   232  				t.Skipf("skipping: %s not available", tt.net)
   233  			}
   234  
   235  			c, err := ListenUDP(tt.net, tt.laddr)
   236  			if err != nil {
   237  				t.Fatal(err)
   238  			}
   239  			defer c.Close()
   240  			la := c.LocalAddr()
   241  			if a, ok := la.(*UDPAddr); !ok || a.Port == 0 {
   242  				t.Fatalf("got %v; expected a proper address with non-zero port number", la)
   243  			}
   244  		})
   245  	}
   246  }
   247  
   248  func TestUDPConnLocalAndRemoteNames(t *testing.T) {
   249  	if !testableNetwork("udp") {
   250  		t.Skipf("skipping: udp not available")
   251  	}
   252  
   253  	for _, laddr := range []string{"", "127.0.0.1:0"} {
   254  		c1, err := ListenPacket("udp", "127.0.0.1:0")
   255  		if err != nil {
   256  			t.Fatal(err)
   257  		}
   258  		defer c1.Close()
   259  
   260  		var la *UDPAddr
   261  		if laddr != "" {
   262  			var err error
   263  			if la, err = ResolveUDPAddr("udp", laddr); err != nil {
   264  				t.Fatal(err)
   265  			}
   266  		}
   267  		c2, err := DialUDP("udp", la, c1.LocalAddr().(*UDPAddr))
   268  		if err != nil {
   269  			t.Fatal(err)
   270  		}
   271  		defer c2.Close()
   272  
   273  		var connAddrs = [4]struct {
   274  			got Addr
   275  			ok  bool
   276  		}{
   277  			{c1.LocalAddr(), true},
   278  			{c1.(*UDPConn).RemoteAddr(), false},
   279  			{c2.LocalAddr(), true},
   280  			{c2.RemoteAddr(), true},
   281  		}
   282  		for _, ca := range connAddrs {
   283  			if a, ok := ca.got.(*UDPAddr); ok != ca.ok || ok && a.Port == 0 {
   284  				t.Fatalf("got %v; expected a proper address with non-zero port number", ca.got)
   285  			}
   286  		}
   287  	}
   288  }
   289  
   290  func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
   291  	testenv.MustHaveExternalNetwork(t)
   292  
   293  	if !supportsIPv6() {
   294  		t.Skip("IPv6 is not supported")
   295  	}
   296  
   297  	for i, tt := range ipv6LinkLocalUnicastUDPTests {
   298  		c1, err := ListenPacket(tt.network, tt.address)
   299  		if err != nil {
   300  			// It might return "LookupHost returned no
   301  			// suitable address" error on some platforms.
   302  			t.Log(err)
   303  			continue
   304  		}
   305  		ls := (&packetListener{PacketConn: c1}).newLocalServer()
   306  		defer ls.teardown()
   307  		ch := make(chan error, 1)
   308  		handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, ch) }
   309  		if err := ls.buildup(handler); err != nil {
   310  			t.Fatal(err)
   311  		}
   312  		if la, ok := c1.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
   313  			t.Fatalf("got %v; expected a proper address with zone identifier", la)
   314  		}
   315  
   316  		c2, err := Dial(tt.network, ls.PacketConn.LocalAddr().String())
   317  		if err != nil {
   318  			t.Fatal(err)
   319  		}
   320  		defer c2.Close()
   321  		if la, ok := c2.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
   322  			t.Fatalf("got %v; expected a proper address with zone identifier", la)
   323  		}
   324  		if ra, ok := c2.RemoteAddr().(*UDPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
   325  			t.Fatalf("got %v; expected a proper address with zone identifier", ra)
   326  		}
   327  
   328  		if _, err := c2.Write([]byte("UDP OVER IPV6 LINKLOCAL TEST")); err != nil {
   329  			t.Fatal(err)
   330  		}
   331  		b := make([]byte, 32)
   332  		if _, err := c2.Read(b); err != nil {
   333  			t.Fatal(err)
   334  		}
   335  
   336  		for err := range ch {
   337  			t.Errorf("#%d: %v", i, err)
   338  		}
   339  	}
   340  }
   341  
   342  func TestUDPZeroBytePayload(t *testing.T) {
   343  	switch runtime.GOOS {
   344  	case "plan9":
   345  		t.Skipf("not supported on %s", runtime.GOOS)
   346  	case "ios":
   347  		testenv.SkipFlaky(t, 29225)
   348  	}
   349  	if !testableNetwork("udp") {
   350  		t.Skipf("skipping: udp not available")
   351  	}
   352  
   353  	c := newLocalPacketListener(t, "udp")
   354  	defer c.Close()
   355  
   356  	for _, genericRead := range []bool{false, true} {
   357  		n, err := c.WriteTo(nil, c.LocalAddr())
   358  		if err != nil {
   359  			t.Fatal(err)
   360  		}
   361  		if n != 0 {
   362  			t.Errorf("got %d; want 0", n)
   363  		}
   364  		c.SetReadDeadline(time.Now().Add(30 * time.Second))
   365  		var b [1]byte
   366  		var name string
   367  		if genericRead {
   368  			_, err = c.(Conn).Read(b[:])
   369  			name = "Read"
   370  		} else {
   371  			_, _, err = c.ReadFrom(b[:])
   372  			name = "ReadFrom"
   373  		}
   374  		if err != nil {
   375  			t.Errorf("%s of zero byte packet failed: %v", name, err)
   376  		}
   377  	}
   378  }
   379  
   380  func TestUDPZeroByteBuffer(t *testing.T) {
   381  	switch runtime.GOOS {
   382  	case "plan9":
   383  		t.Skipf("not supported on %s", runtime.GOOS)
   384  	}
   385  	if !testableNetwork("udp") {
   386  		t.Skipf("skipping: udp not available")
   387  	}
   388  
   389  	c := newLocalPacketListener(t, "udp")
   390  	defer c.Close()
   391  
   392  	b := []byte("UDP ZERO BYTE BUFFER TEST")
   393  	for _, genericRead := range []bool{false, true} {
   394  		n, err := c.WriteTo(b, c.LocalAddr())
   395  		if err != nil {
   396  			t.Fatal(err)
   397  		}
   398  		if n != len(b) {
   399  			t.Errorf("got %d; want %d", n, len(b))
   400  		}
   401  		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
   402  		if genericRead {
   403  			_, err = c.(Conn).Read(nil)
   404  		} else {
   405  			_, _, err = c.ReadFrom(nil)
   406  		}
   407  		switch err {
   408  		case nil: // ReadFrom succeeds
   409  		default: // Read may timeout, it depends on the platform
   410  			if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZE
   411  				t.Fatal(err)
   412  			}
   413  		}
   414  	}
   415  }
   416  
   417  func TestUDPReadSizeError(t *testing.T) {
   418  	switch runtime.GOOS {
   419  	case "plan9":
   420  		t.Skipf("not supported on %s", runtime.GOOS)
   421  	}
   422  	if !testableNetwork("udp") {
   423  		t.Skipf("skipping: udp not available")
   424  	}
   425  
   426  	c1 := newLocalPacketListener(t, "udp")
   427  	defer c1.Close()
   428  
   429  	c2, err := Dial("udp", c1.LocalAddr().String())
   430  	if err != nil {
   431  		t.Fatal(err)
   432  	}
   433  	defer c2.Close()
   434  
   435  	b1 := []byte("READ SIZE ERROR TEST")
   436  	for _, genericRead := range []bool{false, true} {
   437  		n, err := c2.Write(b1)
   438  		if err != nil {
   439  			t.Fatal(err)
   440  		}
   441  		if n != len(b1) {
   442  			t.Errorf("got %d; want %d", n, len(b1))
   443  		}
   444  		b2 := make([]byte, len(b1)-1)
   445  		if genericRead {
   446  			n, err = c1.(Conn).Read(b2)
   447  		} else {
   448  			n, _, err = c1.ReadFrom(b2)
   449  		}
   450  		if err != nil && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZE
   451  			t.Fatal(err)
   452  		}
   453  		if n != len(b1)-1 {
   454  			t.Fatalf("got %d; want %d", n, len(b1)-1)
   455  		}
   456  	}
   457  }
   458  
   459  // TestUDPReadTimeout verifies that ReadFromUDP with timeout returns an error
   460  // without data or an address.
   461  func TestUDPReadTimeout(t *testing.T) {
   462  	if !testableNetwork("udp4") {
   463  		t.Skipf("skipping: udp4 not available")
   464  	}
   465  
   466  	la, err := ResolveUDPAddr("udp4", "127.0.0.1:0")
   467  	if err != nil {
   468  		t.Fatal(err)
   469  	}
   470  	c, err := ListenUDP("udp4", la)
   471  	if err != nil {
   472  		t.Fatal(err)
   473  	}
   474  	defer c.Close()
   475  
   476  	c.SetDeadline(time.Now())
   477  	b := make([]byte, 1)
   478  	n, addr, err := c.ReadFromUDP(b)
   479  	if !errors.Is(err, os.ErrDeadlineExceeded) {
   480  		t.Errorf("ReadFromUDP got err %v want os.ErrDeadlineExceeded", err)
   481  	}
   482  	if n != 0 {
   483  		t.Errorf("ReadFromUDP got n %d want 0", n)
   484  	}
   485  	if addr != nil {
   486  		t.Errorf("ReadFromUDP got addr %+#v want nil", addr)
   487  	}
   488  }
   489  
   490  func TestAllocs(t *testing.T) {
   491  	switch runtime.GOOS {
   492  	case "plan9", "js", "wasip1":
   493  		// These implementations have not been optimized.
   494  		t.Skipf("skipping on %v", runtime.GOOS)
   495  	case "windows":
   496  		if race.Enabled {
   497  			// The Windows implementation make use of sync.Pool,
   498  			// which randomly drops cached items when race is enabled.
   499  			t.Skip("skipping test in race")
   500  		}
   501  	}
   502  	if !testableNetwork("udp4") {
   503  		t.Skipf("skipping: udp4 not available")
   504  	}
   505  	if asan.Enabled {
   506  		t.Skip("test allocates more with -asan; see #70079")
   507  	}
   508  
   509  	// Optimizations are required to remove the allocs.
   510  	testenv.SkipIfOptimizationOff(t)
   511  
   512  	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
   513  	if err != nil {
   514  		t.Fatal(err)
   515  	}
   516  	defer conn.Close()
   517  	addr := conn.LocalAddr()
   518  	addrPort := addr.(*UDPAddr).AddrPort()
   519  	buf := make([]byte, 8)
   520  
   521  	allocs := testing.AllocsPerRun(1000, func() {
   522  		_, _, err := conn.WriteMsgUDPAddrPort(buf, nil, addrPort)
   523  		if err != nil {
   524  			t.Fatal(err)
   525  		}
   526  		_, _, _, _, err = conn.ReadMsgUDPAddrPort(buf, nil)
   527  		if err != nil {
   528  			t.Fatal(err)
   529  		}
   530  	})
   531  	if got := int(allocs); got != 0 {
   532  		t.Errorf("WriteMsgUDPAddrPort/ReadMsgUDPAddrPort allocated %d objects", got)
   533  	}
   534  
   535  	allocs = testing.AllocsPerRun(1000, func() {
   536  		_, err := conn.WriteToUDPAddrPort(buf, addrPort)
   537  		if err != nil {
   538  			t.Fatal(err)
   539  		}
   540  		_, _, err = conn.ReadFromUDPAddrPort(buf)
   541  		if err != nil {
   542  			t.Fatal(err)
   543  		}
   544  	})
   545  	if got := int(allocs); got != 0 {
   546  		t.Errorf("WriteToUDPAddrPort/ReadFromUDPAddrPort allocated %d objects", got)
   547  	}
   548  
   549  	allocs = testing.AllocsPerRun(1000, func() {
   550  		_, err := conn.WriteTo(buf, addr)
   551  		if err != nil {
   552  			t.Fatal(err)
   553  		}
   554  		_, _, err = conn.ReadFromUDP(buf)
   555  		if err != nil {
   556  			t.Fatal(err)
   557  		}
   558  	})
   559  	if got := int(allocs); got != 1 {
   560  		t.Errorf("WriteTo/ReadFromUDP allocated %d objects", got)
   561  	}
   562  }
   563  
   564  func BenchmarkReadWriteMsgUDPAddrPort(b *testing.B) {
   565  	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
   566  	if err != nil {
   567  		b.Fatal(err)
   568  	}
   569  	defer conn.Close()
   570  	addr := conn.LocalAddr().(*UDPAddr).AddrPort()
   571  	buf := make([]byte, 8)
   572  	b.ResetTimer()
   573  	b.ReportAllocs()
   574  	for i := 0; i < b.N; i++ {
   575  		_, _, err := conn.WriteMsgUDPAddrPort(buf, nil, addr)
   576  		if err != nil {
   577  			b.Fatal(err)
   578  		}
   579  		_, _, _, _, err = conn.ReadMsgUDPAddrPort(buf, nil)
   580  		if err != nil {
   581  			b.Fatal(err)
   582  		}
   583  	}
   584  }
   585  
   586  func BenchmarkWriteToReadFromUDP(b *testing.B) {
   587  	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
   588  	if err != nil {
   589  		b.Fatal(err)
   590  	}
   591  	defer conn.Close()
   592  	addr := conn.LocalAddr()
   593  	buf := make([]byte, 8)
   594  	b.ResetTimer()
   595  	b.ReportAllocs()
   596  	for i := 0; i < b.N; i++ {
   597  		_, err := conn.WriteTo(buf, addr)
   598  		if err != nil {
   599  			b.Fatal(err)
   600  		}
   601  		_, _, err = conn.ReadFromUDP(buf)
   602  		if err != nil {
   603  			b.Fatal(err)
   604  		}
   605  	}
   606  }
   607  
   608  func BenchmarkWriteToReadFromUDPAddrPort(b *testing.B) {
   609  	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
   610  	if err != nil {
   611  		b.Fatal(err)
   612  	}
   613  	defer conn.Close()
   614  	addr := conn.LocalAddr().(*UDPAddr).AddrPort()
   615  	buf := make([]byte, 8)
   616  	b.ResetTimer()
   617  	b.ReportAllocs()
   618  	for i := 0; i < b.N; i++ {
   619  		_, err := conn.WriteToUDPAddrPort(buf, addr)
   620  		if err != nil {
   621  			b.Fatal(err)
   622  		}
   623  		_, _, err = conn.ReadFromUDPAddrPort(buf)
   624  		if err != nil {
   625  			b.Fatal(err)
   626  		}
   627  	}
   628  }
   629  
   630  func TestUDPIPVersionReadMsg(t *testing.T) {
   631  	switch runtime.GOOS {
   632  	case "plan9":
   633  		t.Skipf("skipping on %v", runtime.GOOS)
   634  	}
   635  	if !testableNetwork("udp4") {
   636  		t.Skipf("skipping: udp4 not available")
   637  	}
   638  
   639  	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
   640  	if err != nil {
   641  		t.Fatal(err)
   642  	}
   643  	defer conn.Close()
   644  	daddr := conn.LocalAddr().(*UDPAddr).AddrPort()
   645  	buf := make([]byte, 8)
   646  	_, err = conn.WriteToUDPAddrPort(buf, daddr)
   647  	if err != nil {
   648  		t.Fatal(err)
   649  	}
   650  	_, _, _, saddr, err := conn.ReadMsgUDPAddrPort(buf, nil)
   651  	if err != nil {
   652  		t.Fatal(err)
   653  	}
   654  	if !saddr.Addr().Is4() {
   655  		t.Error("returned AddrPort is not IPv4")
   656  	}
   657  	_, err = conn.WriteToUDPAddrPort(buf, daddr)
   658  	if err != nil {
   659  		t.Fatal(err)
   660  	}
   661  	_, _, _, soldaddr, err := conn.ReadMsgUDP(buf, nil)
   662  	if err != nil {
   663  		t.Fatal(err)
   664  	}
   665  	if len(soldaddr.IP) != 4 {
   666  		t.Error("returned UDPAddr is not IPv4")
   667  	}
   668  }
   669  
   670  // TestIPv6WriteMsgUDPAddrPortTargetAddrIPVersion verifies that
   671  // WriteMsgUDPAddrPort accepts IPv4, IPv4-mapped IPv6, and IPv6 target addresses
   672  // on a UDPConn listening on "::".
   673  func TestIPv6WriteMsgUDPAddrPortTargetAddrIPVersion(t *testing.T) {
   674  	if !testableNetwork("udp4") {
   675  		t.Skipf("skipping: udp4 not available")
   676  	}
   677  	if !testableNetwork("udp6") {
   678  		t.Skipf("skipping: udp6 not available")
   679  	}
   680  
   681  	switch runtime.GOOS {
   682  	case "dragonfly", "openbsd":
   683  		// DragonflyBSD's IPv6 sockets are always IPv6-only, according to the man page:
   684  		// https://www.dragonflybsd.org/cgi/web-man?command=ip6 (search for IPV6_V6ONLY).
   685  		// OpenBSD's IPv6 sockets are always IPv6-only, according to the man page:
   686  		// https://man.openbsd.org/ip6#IPV6_V6ONLY
   687  		t.Skipf("skipping on %v", runtime.GOOS)
   688  	}
   689  
   690  	conn, err := ListenUDP("udp", nil)
   691  	if err != nil {
   692  		t.Fatal(err)
   693  	}
   694  	defer conn.Close()
   695  
   696  	daddr4 := netip.AddrPortFrom(netip.MustParseAddr("127.0.0.1"), 12345)
   697  	daddr4in6 := netip.AddrPortFrom(netip.MustParseAddr("::ffff:127.0.0.1"), 12345)
   698  	daddr6 := netip.AddrPortFrom(netip.MustParseAddr("::1"), 12345)
   699  	buf := make([]byte, 8)
   700  
   701  	_, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4)
   702  	if err != nil {
   703  		t.Fatal(err)
   704  	}
   705  
   706  	_, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4in6)
   707  	if err != nil {
   708  		t.Fatal(err)
   709  	}
   710  
   711  	_, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr6)
   712  	if err != nil {
   713  		t.Fatal(err)
   714  	}
   715  }
   716  
   717  // TestIPv4WriteMsgUDPAddrPortTargetAddrIPVersion verifies that
   718  // WriteMsgUDPAddrPort accepts IPv4 and IPv4-mapped IPv6 destination addresses,
   719  // and rejects IPv6 destination addresses on a "udp4" connection.
   720  func TestIPv4WriteMsgUDPAddrPortTargetAddrIPVersion(t *testing.T) {
   721  	switch runtime.GOOS {
   722  	case "plan9":
   723  		t.Skipf("not supported on %s", runtime.GOOS)
   724  	}
   725  
   726  	if !testableNetwork("udp4") {
   727  		t.Skipf("skipping: udp4 not available")
   728  	}
   729  
   730  	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
   731  	if err != nil {
   732  		t.Fatal(err)
   733  	}
   734  	defer conn.Close()
   735  
   736  	daddr4 := netip.AddrPortFrom(netip.MustParseAddr("127.0.0.1"), 12345)
   737  	daddr4in6 := netip.AddrPortFrom(netip.MustParseAddr("::ffff:127.0.0.1"), 12345)
   738  	daddr6 := netip.AddrPortFrom(netip.MustParseAddr("::1"), 12345)
   739  	buf := make([]byte, 8)
   740  
   741  	if _, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4); err != nil {
   742  		t.Errorf("conn.WriteMsgUDPAddrPort(buf, nil, daddr4) failed: %v", err)
   743  	}
   744  
   745  	if _, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4in6); err != nil {
   746  		t.Errorf("conn.WriteMsgUDPAddrPort(buf, nil, daddr4in6) failed: %v", err)
   747  	}
   748  
   749  	if _, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr6); err == nil {
   750  		t.Errorf("conn.WriteMsgUDPAddrPort(buf, nil, daddr6) should have failed, but got no error")
   751  	}
   752  }
   753  

View as plain text