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  	for _, network := range []string{"udp4", "udp6"} {
   121  		t.Run(network, func(t *testing.T) {
   122  			if !testableNetwork(network) {
   123  				t.Skipf("skipping: %s not supported", network)
   124  			}
   125  
   126  			c, err := ListenPacket(network, JoinHostPort(loopbackIP(network).String(), "0"))
   127  			if err != nil {
   128  				t.Fatal(err)
   129  			}
   130  			defer c.Close()
   131  
   132  			testWriteToConn(t, network, c.LocalAddr().String())
   133  			testWriteToPacketConn(t, network, c.LocalAddr().String())
   134  		})
   135  	}
   136  }
   137  
   138  func testWriteToConn(t *testing.T, network, raddr string) {
   139  	c, err := Dial(network, raddr)
   140  	if err != nil {
   141  		t.Fatal(err)
   142  	}
   143  	defer c.Close()
   144  
   145  	ra, err := ResolveUDPAddr(network, raddr)
   146  	if err != nil {
   147  		t.Fatal(err)
   148  	}
   149  	rap := ra.AddrPort()
   150  
   151  	assertErrWriteToConnected := func(t *testing.T, err error) {
   152  		t.Helper()
   153  		if e, ok := err.(*OpError); !ok || e.Err != ErrWriteToConnected {
   154  			t.Errorf("got %v; want ErrWriteToConnected", err)
   155  		}
   156  	}
   157  
   158  	b := []byte("CONNECTED-MODE SOCKET")
   159  	_, err = c.(*UDPConn).WriteToUDPAddrPort(b, rap)
   160  	assertErrWriteToConnected(t, err)
   161  	_, err = c.(*UDPConn).WriteToUDP(b, ra)
   162  	assertErrWriteToConnected(t, err)
   163  	_, err = c.(*UDPConn).WriteTo(b, ra)
   164  	assertErrWriteToConnected(t, err)
   165  	_, err = c.Write(b)
   166  	if err != nil {
   167  		t.Errorf("c.Write(b) = %v; want nil", err)
   168  	}
   169  	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra)
   170  	assertErrWriteToConnected(t, err)
   171  	n, oobn, err := c.(*UDPConn).WriteMsgUDP(b, nil, nil)
   172  	if err != nil {
   173  		t.Errorf("c.WriteMsgUDP(b, nil, nil) = %v; want nil", err)
   174  	}
   175  	if n != len(b) || oobn != 0 {
   176  		t.Errorf("c.WriteMsgUDP(b, nil, nil) = %d, %d; want %d, 0", n, oobn, len(b))
   177  	}
   178  	_, _, err = c.(*UDPConn).WriteMsgUDPAddrPort(b, nil, rap)
   179  	assertErrWriteToConnected(t, err)
   180  	n, oobn, err = c.(*UDPConn).WriteMsgUDPAddrPort(b, nil, netip.AddrPort{})
   181  	if err != nil {
   182  		t.Errorf("c.WriteMsgUDPAddrPort(b, nil, netip.AddrPort{}) = %v; want nil", err)
   183  	}
   184  	if n != len(b) || oobn != 0 {
   185  		t.Errorf("c.WriteMsgUDPAddrPort(b, nil, netip.AddrPort{}) = %d, %d; want %d, 0", n, oobn, len(b))
   186  	}
   187  }
   188  
   189  func testWriteToPacketConn(t *testing.T, network, raddr string) {
   190  	c, err := ListenPacket(network, JoinHostPort(loopbackIP(network).String(), "0"))
   191  	if err != nil {
   192  		t.Fatal(err)
   193  	}
   194  	defer c.Close()
   195  
   196  	ra, err := ResolveUDPAddr(network, raddr)
   197  	if err != nil {
   198  		t.Fatal(err)
   199  	}
   200  
   201  	b := []byte("UNCONNECTED-MODE SOCKET")
   202  	_, err = c.(*UDPConn).WriteToUDP(b, ra)
   203  	if err != nil {
   204  		t.Fatal(err)
   205  	}
   206  	_, err = c.WriteTo(b, ra)
   207  	if err != nil {
   208  		t.Fatal(err)
   209  	}
   210  	_, err = c.(*UDPConn).Write(b)
   211  	if err == nil {
   212  		t.Fatal("should fail")
   213  	}
   214  	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
   215  	if err == nil {
   216  		t.Fatal("should fail")
   217  	}
   218  	if err != nil && err.(*OpError).Err != errMissingAddress {
   219  		t.Fatalf("should fail as errMissingAddress: %v", err)
   220  	}
   221  	n, oobn, err := c.(*UDPConn).WriteMsgUDP(b, nil, ra)
   222  	if err != nil {
   223  		t.Fatal(err)
   224  	}
   225  	if n != len(b) || oobn != 0 {
   226  		t.Errorf("c.WriteMsgUDP(b, nil, ra) = %d, %d; want %d, 0", n, oobn, len(b))
   227  	}
   228  	n, oobn, err = c.(*UDPConn).WriteMsgUDPAddrPort(b, nil, ra.AddrPort())
   229  	if err != nil {
   230  		t.Fatal(err)
   231  	}
   232  	if n != len(b) || oobn != 0 {
   233  		t.Errorf("c.WriteMsgUDPAddrPort(b, nil, ra.AddrPort()) = %d, %d; want %d, 0", n, oobn, len(b))
   234  	}
   235  }
   236  
   237  var udpConnLocalNameTests = []struct {
   238  	net   string
   239  	laddr *UDPAddr
   240  }{
   241  	{"udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)}},
   242  	{"udp4", &UDPAddr{}},
   243  	{"udp4", nil},
   244  }
   245  
   246  func TestUDPConnLocalName(t *testing.T) {
   247  	testenv.MustHaveExternalNetwork(t)
   248  
   249  	for _, tt := range udpConnLocalNameTests {
   250  		t.Run(fmt.Sprint(tt.laddr), func(t *testing.T) {
   251  			if !testableNetwork(tt.net) {
   252  				t.Skipf("skipping: %s not available", tt.net)
   253  			}
   254  
   255  			c, err := ListenUDP(tt.net, tt.laddr)
   256  			if err != nil {
   257  				t.Fatal(err)
   258  			}
   259  			defer c.Close()
   260  			la := c.LocalAddr()
   261  			if a, ok := la.(*UDPAddr); !ok || a.Port == 0 {
   262  				t.Fatalf("got %v; expected a proper address with non-zero port number", la)
   263  			}
   264  		})
   265  	}
   266  }
   267  
   268  func TestUDPConnLocalAndRemoteNames(t *testing.T) {
   269  	if !testableNetwork("udp") {
   270  		t.Skipf("skipping: udp not available")
   271  	}
   272  
   273  	for _, laddr := range []string{"", "127.0.0.1:0"} {
   274  		c1, err := ListenPacket("udp", "127.0.0.1:0")
   275  		if err != nil {
   276  			t.Fatal(err)
   277  		}
   278  		defer c1.Close()
   279  
   280  		var la *UDPAddr
   281  		if laddr != "" {
   282  			var err error
   283  			if la, err = ResolveUDPAddr("udp", laddr); err != nil {
   284  				t.Fatal(err)
   285  			}
   286  		}
   287  		c2, err := DialUDP("udp", la, c1.LocalAddr().(*UDPAddr))
   288  		if err != nil {
   289  			t.Fatal(err)
   290  		}
   291  		defer c2.Close()
   292  
   293  		var connAddrs = [4]struct {
   294  			got Addr
   295  			ok  bool
   296  		}{
   297  			{c1.LocalAddr(), true},
   298  			{c1.(*UDPConn).RemoteAddr(), false},
   299  			{c2.LocalAddr(), true},
   300  			{c2.RemoteAddr(), true},
   301  		}
   302  		for _, ca := range connAddrs {
   303  			if a, ok := ca.got.(*UDPAddr); ok != ca.ok || ok && a.Port == 0 {
   304  				t.Fatalf("got %v; expected a proper address with non-zero port number", ca.got)
   305  			}
   306  		}
   307  	}
   308  }
   309  
   310  func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
   311  	testenv.MustHaveExternalNetwork(t)
   312  
   313  	if !supportsIPv6() {
   314  		t.Skip("IPv6 is not supported")
   315  	}
   316  
   317  	for i, tt := range ipv6LinkLocalUnicastUDPTests {
   318  		c1, err := ListenPacket(tt.network, tt.address)
   319  		if err != nil {
   320  			// It might return "LookupHost returned no
   321  			// suitable address" error on some platforms.
   322  			t.Log(err)
   323  			continue
   324  		}
   325  		ls := (&packetListener{PacketConn: c1}).newLocalServer()
   326  		defer ls.teardown()
   327  		ch := make(chan error, 1)
   328  		handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, ch) }
   329  		if err := ls.buildup(handler); err != nil {
   330  			t.Fatal(err)
   331  		}
   332  		if la, ok := c1.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
   333  			t.Fatalf("got %v; expected a proper address with zone identifier", la)
   334  		}
   335  
   336  		c2, err := Dial(tt.network, ls.PacketConn.LocalAddr().String())
   337  		if err != nil {
   338  			t.Fatal(err)
   339  		}
   340  		defer c2.Close()
   341  		if la, ok := c2.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
   342  			t.Fatalf("got %v; expected a proper address with zone identifier", la)
   343  		}
   344  		if ra, ok := c2.RemoteAddr().(*UDPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
   345  			t.Fatalf("got %v; expected a proper address with zone identifier", ra)
   346  		}
   347  
   348  		if _, err := c2.Write([]byte("UDP OVER IPV6 LINKLOCAL TEST")); err != nil {
   349  			t.Fatal(err)
   350  		}
   351  		b := make([]byte, 32)
   352  		if _, err := c2.Read(b); err != nil {
   353  			t.Fatal(err)
   354  		}
   355  
   356  		for err := range ch {
   357  			t.Errorf("#%d: %v", i, err)
   358  		}
   359  	}
   360  }
   361  
   362  func TestUDPZeroBytePayload(t *testing.T) {
   363  	switch runtime.GOOS {
   364  	case "plan9":
   365  		t.Skipf("not supported on %s", runtime.GOOS)
   366  	case "ios":
   367  		testenv.SkipFlaky(t, 29225)
   368  	}
   369  	if !testableNetwork("udp") {
   370  		t.Skipf("skipping: udp not available")
   371  	}
   372  
   373  	c := newLocalPacketListener(t, "udp")
   374  	defer c.Close()
   375  
   376  	for _, genericRead := range []bool{false, true} {
   377  		n, err := c.WriteTo(nil, c.LocalAddr())
   378  		if err != nil {
   379  			t.Fatal(err)
   380  		}
   381  		if n != 0 {
   382  			t.Errorf("got %d; want 0", n)
   383  		}
   384  		c.SetReadDeadline(time.Now().Add(30 * time.Second))
   385  		var b [1]byte
   386  		var name string
   387  		if genericRead {
   388  			_, err = c.(Conn).Read(b[:])
   389  			name = "Read"
   390  		} else {
   391  			_, _, err = c.ReadFrom(b[:])
   392  			name = "ReadFrom"
   393  		}
   394  		if err != nil {
   395  			t.Errorf("%s of zero byte packet failed: %v", name, err)
   396  		}
   397  	}
   398  }
   399  
   400  func TestUDPZeroByteBuffer(t *testing.T) {
   401  	switch runtime.GOOS {
   402  	case "plan9":
   403  		t.Skipf("not supported on %s", runtime.GOOS)
   404  	}
   405  	if !testableNetwork("udp") {
   406  		t.Skipf("skipping: udp not available")
   407  	}
   408  
   409  	c := newLocalPacketListener(t, "udp")
   410  	defer c.Close()
   411  
   412  	b := []byte("UDP ZERO BYTE BUFFER TEST")
   413  	for _, genericRead := range []bool{false, true} {
   414  		n, err := c.WriteTo(b, c.LocalAddr())
   415  		if err != nil {
   416  			t.Fatal(err)
   417  		}
   418  		if n != len(b) {
   419  			t.Errorf("got %d; want %d", n, len(b))
   420  		}
   421  		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
   422  		if genericRead {
   423  			_, err = c.(Conn).Read(nil)
   424  		} else {
   425  			_, _, err = c.ReadFrom(nil)
   426  		}
   427  		switch err {
   428  		case nil: // ReadFrom succeeds
   429  		default: // Read may timeout, it depends on the platform
   430  			if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZE
   431  				t.Fatal(err)
   432  			}
   433  		}
   434  	}
   435  }
   436  
   437  func TestUDPReadSizeError(t *testing.T) {
   438  	switch runtime.GOOS {
   439  	case "plan9":
   440  		t.Skipf("not supported on %s", runtime.GOOS)
   441  	}
   442  	if !testableNetwork("udp") {
   443  		t.Skipf("skipping: udp not available")
   444  	}
   445  
   446  	c1 := newLocalPacketListener(t, "udp")
   447  	defer c1.Close()
   448  
   449  	c2, err := Dial("udp", c1.LocalAddr().String())
   450  	if err != nil {
   451  		t.Fatal(err)
   452  	}
   453  	defer c2.Close()
   454  
   455  	b1 := []byte("READ SIZE ERROR TEST")
   456  	for _, genericRead := range []bool{false, true} {
   457  		n, err := c2.Write(b1)
   458  		if err != nil {
   459  			t.Fatal(err)
   460  		}
   461  		if n != len(b1) {
   462  			t.Errorf("got %d; want %d", n, len(b1))
   463  		}
   464  		b2 := make([]byte, len(b1)-1)
   465  		if genericRead {
   466  			n, err = c1.(Conn).Read(b2)
   467  		} else {
   468  			n, _, err = c1.ReadFrom(b2)
   469  		}
   470  		if err != nil && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZE
   471  			t.Fatal(err)
   472  		}
   473  		if n != len(b1)-1 {
   474  			t.Fatalf("got %d; want %d", n, len(b1)-1)
   475  		}
   476  	}
   477  }
   478  
   479  // TestUDPReadTimeout verifies that ReadFromUDP with timeout returns an error
   480  // without data or an address.
   481  func TestUDPReadTimeout(t *testing.T) {
   482  	if !testableNetwork("udp4") {
   483  		t.Skipf("skipping: udp4 not available")
   484  	}
   485  
   486  	la, err := ResolveUDPAddr("udp4", "127.0.0.1:0")
   487  	if err != nil {
   488  		t.Fatal(err)
   489  	}
   490  	c, err := ListenUDP("udp4", la)
   491  	if err != nil {
   492  		t.Fatal(err)
   493  	}
   494  	defer c.Close()
   495  
   496  	c.SetDeadline(time.Now())
   497  	b := make([]byte, 1)
   498  	n, addr, err := c.ReadFromUDP(b)
   499  	if !errors.Is(err, os.ErrDeadlineExceeded) {
   500  		t.Errorf("ReadFromUDP got err %v want os.ErrDeadlineExceeded", err)
   501  	}
   502  	if n != 0 {
   503  		t.Errorf("ReadFromUDP got n %d want 0", n)
   504  	}
   505  	if addr != nil {
   506  		t.Errorf("ReadFromUDP got addr %+#v want nil", addr)
   507  	}
   508  }
   509  
   510  func TestAllocs(t *testing.T) {
   511  	switch runtime.GOOS {
   512  	case "plan9", "js", "wasip1":
   513  		// These implementations have not been optimized.
   514  		t.Skipf("skipping on %v", runtime.GOOS)
   515  	case "windows":
   516  		if race.Enabled {
   517  			// The Windows implementation make use of sync.Pool,
   518  			// which randomly drops cached items when race is enabled.
   519  			t.Skip("skipping test in race")
   520  		}
   521  	}
   522  	if !testableNetwork("udp4") {
   523  		t.Skipf("skipping: udp4 not available")
   524  	}
   525  	if asan.Enabled {
   526  		t.Skip("test allocates more with -asan; see #70079")
   527  	}
   528  
   529  	// Optimizations are required to remove the allocs.
   530  	testenv.SkipIfOptimizationOff(t)
   531  
   532  	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
   533  	if err != nil {
   534  		t.Fatal(err)
   535  	}
   536  	defer conn.Close()
   537  	addr := conn.LocalAddr()
   538  	addrPort := addr.(*UDPAddr).AddrPort()
   539  	buf := make([]byte, 8)
   540  
   541  	allocs := testing.AllocsPerRun(1000, func() {
   542  		_, _, err := conn.WriteMsgUDPAddrPort(buf, nil, addrPort)
   543  		if err != nil {
   544  			t.Fatal(err)
   545  		}
   546  		_, _, _, _, err = conn.ReadMsgUDPAddrPort(buf, nil)
   547  		if err != nil {
   548  			t.Fatal(err)
   549  		}
   550  	})
   551  	if got := int(allocs); got != 0 {
   552  		t.Errorf("WriteMsgUDPAddrPort/ReadMsgUDPAddrPort allocated %d objects", got)
   553  	}
   554  
   555  	allocs = testing.AllocsPerRun(1000, func() {
   556  		_, err := conn.WriteToUDPAddrPort(buf, addrPort)
   557  		if err != nil {
   558  			t.Fatal(err)
   559  		}
   560  		_, _, err = conn.ReadFromUDPAddrPort(buf)
   561  		if err != nil {
   562  			t.Fatal(err)
   563  		}
   564  	})
   565  	if got := int(allocs); got != 0 {
   566  		t.Errorf("WriteToUDPAddrPort/ReadFromUDPAddrPort allocated %d objects", got)
   567  	}
   568  
   569  	allocs = testing.AllocsPerRun(1000, func() {
   570  		_, err := conn.WriteTo(buf, addr)
   571  		if err != nil {
   572  			t.Fatal(err)
   573  		}
   574  		_, _, err = conn.ReadFromUDP(buf)
   575  		if err != nil {
   576  			t.Fatal(err)
   577  		}
   578  	})
   579  	if got := int(allocs); got != 1 {
   580  		t.Errorf("WriteTo/ReadFromUDP allocated %d objects", got)
   581  	}
   582  }
   583  
   584  func BenchmarkReadWriteMsgUDPAddrPort(b *testing.B) {
   585  	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
   586  	if err != nil {
   587  		b.Fatal(err)
   588  	}
   589  	defer conn.Close()
   590  	addr := conn.LocalAddr().(*UDPAddr).AddrPort()
   591  	buf := make([]byte, 8)
   592  	b.ResetTimer()
   593  	b.ReportAllocs()
   594  	for i := 0; i < b.N; i++ {
   595  		_, _, err := conn.WriteMsgUDPAddrPort(buf, nil, addr)
   596  		if err != nil {
   597  			b.Fatal(err)
   598  		}
   599  		_, _, _, _, err = conn.ReadMsgUDPAddrPort(buf, nil)
   600  		if err != nil {
   601  			b.Fatal(err)
   602  		}
   603  	}
   604  }
   605  
   606  func BenchmarkWriteToReadFromUDP(b *testing.B) {
   607  	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
   608  	if err != nil {
   609  		b.Fatal(err)
   610  	}
   611  	defer conn.Close()
   612  	addr := conn.LocalAddr()
   613  	buf := make([]byte, 8)
   614  	b.ResetTimer()
   615  	b.ReportAllocs()
   616  	for i := 0; i < b.N; i++ {
   617  		_, err := conn.WriteTo(buf, addr)
   618  		if err != nil {
   619  			b.Fatal(err)
   620  		}
   621  		_, _, err = conn.ReadFromUDP(buf)
   622  		if err != nil {
   623  			b.Fatal(err)
   624  		}
   625  	}
   626  }
   627  
   628  func BenchmarkWriteToReadFromUDPAddrPort(b *testing.B) {
   629  	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
   630  	if err != nil {
   631  		b.Fatal(err)
   632  	}
   633  	defer conn.Close()
   634  	addr := conn.LocalAddr().(*UDPAddr).AddrPort()
   635  	buf := make([]byte, 8)
   636  	b.ResetTimer()
   637  	b.ReportAllocs()
   638  	for i := 0; i < b.N; i++ {
   639  		_, err := conn.WriteToUDPAddrPort(buf, addr)
   640  		if err != nil {
   641  			b.Fatal(err)
   642  		}
   643  		_, _, err = conn.ReadFromUDPAddrPort(buf)
   644  		if err != nil {
   645  			b.Fatal(err)
   646  		}
   647  	}
   648  }
   649  
   650  func TestUDPIPVersionReadMsg(t *testing.T) {
   651  	switch runtime.GOOS {
   652  	case "plan9":
   653  		t.Skipf("skipping on %v", runtime.GOOS)
   654  	}
   655  	if !testableNetwork("udp4") {
   656  		t.Skipf("skipping: udp4 not available")
   657  	}
   658  
   659  	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
   660  	if err != nil {
   661  		t.Fatal(err)
   662  	}
   663  	defer conn.Close()
   664  	daddr := conn.LocalAddr().(*UDPAddr).AddrPort()
   665  	buf := make([]byte, 8)
   666  	_, err = conn.WriteToUDPAddrPort(buf, daddr)
   667  	if err != nil {
   668  		t.Fatal(err)
   669  	}
   670  	_, _, _, saddr, err := conn.ReadMsgUDPAddrPort(buf, nil)
   671  	if err != nil {
   672  		t.Fatal(err)
   673  	}
   674  	if !saddr.Addr().Is4() {
   675  		t.Error("returned AddrPort is not IPv4")
   676  	}
   677  	_, err = conn.WriteToUDPAddrPort(buf, daddr)
   678  	if err != nil {
   679  		t.Fatal(err)
   680  	}
   681  	_, _, _, soldaddr, err := conn.ReadMsgUDP(buf, nil)
   682  	if err != nil {
   683  		t.Fatal(err)
   684  	}
   685  	if len(soldaddr.IP) != 4 {
   686  		t.Error("returned UDPAddr is not IPv4")
   687  	}
   688  }
   689  
   690  // TestIPv6WriteMsgUDPAddrPortTargetAddrIPVersion verifies that
   691  // WriteMsgUDPAddrPort accepts IPv4, IPv4-mapped IPv6, and IPv6 target addresses
   692  // on a UDPConn listening on "::".
   693  func TestIPv6WriteMsgUDPAddrPortTargetAddrIPVersion(t *testing.T) {
   694  	if !testableNetwork("udp4") {
   695  		t.Skipf("skipping: udp4 not available")
   696  	}
   697  	if !testableNetwork("udp6") {
   698  		t.Skipf("skipping: udp6 not available")
   699  	}
   700  
   701  	switch runtime.GOOS {
   702  	case "dragonfly", "openbsd":
   703  		// DragonflyBSD's IPv6 sockets are always IPv6-only, according to the man page:
   704  		// https://www.dragonflybsd.org/cgi/web-man?command=ip6 (search for IPV6_V6ONLY).
   705  		// OpenBSD's IPv6 sockets are always IPv6-only, according to the man page:
   706  		// https://man.openbsd.org/ip6#IPV6_V6ONLY
   707  		t.Skipf("skipping on %v", runtime.GOOS)
   708  	}
   709  
   710  	conn, err := ListenUDP("udp", nil)
   711  	if err != nil {
   712  		t.Fatal(err)
   713  	}
   714  	defer conn.Close()
   715  
   716  	daddr4 := netip.AddrPortFrom(netip.MustParseAddr("127.0.0.1"), 12345)
   717  	daddr4in6 := netip.AddrPortFrom(netip.MustParseAddr("::ffff:127.0.0.1"), 12345)
   718  	daddr6 := netip.AddrPortFrom(netip.MustParseAddr("::1"), 12345)
   719  	buf := make([]byte, 8)
   720  
   721  	_, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4)
   722  	if err != nil {
   723  		t.Fatal(err)
   724  	}
   725  
   726  	_, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4in6)
   727  	if err != nil {
   728  		t.Fatal(err)
   729  	}
   730  
   731  	_, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr6)
   732  	if err != nil {
   733  		t.Fatal(err)
   734  	}
   735  }
   736  
   737  // TestIPv4WriteMsgUDPAddrPortTargetAddrIPVersion verifies that
   738  // WriteMsgUDPAddrPort accepts IPv4 and IPv4-mapped IPv6 destination addresses,
   739  // and rejects IPv6 destination addresses on a "udp4" connection.
   740  func TestIPv4WriteMsgUDPAddrPortTargetAddrIPVersion(t *testing.T) {
   741  	switch runtime.GOOS {
   742  	case "plan9":
   743  		t.Skipf("not supported on %s", runtime.GOOS)
   744  	}
   745  
   746  	if !testableNetwork("udp4") {
   747  		t.Skipf("skipping: udp4 not available")
   748  	}
   749  
   750  	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
   751  	if err != nil {
   752  		t.Fatal(err)
   753  	}
   754  	defer conn.Close()
   755  
   756  	daddr4 := netip.AddrPortFrom(netip.MustParseAddr("127.0.0.1"), 12345)
   757  	daddr4in6 := netip.AddrPortFrom(netip.MustParseAddr("::ffff:127.0.0.1"), 12345)
   758  	daddr6 := netip.AddrPortFrom(netip.MustParseAddr("::1"), 12345)
   759  	buf := make([]byte, 8)
   760  
   761  	if _, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4); err != nil {
   762  		t.Errorf("conn.WriteMsgUDPAddrPort(buf, nil, daddr4) failed: %v", err)
   763  	}
   764  
   765  	if _, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr4in6); err != nil {
   766  		t.Errorf("conn.WriteMsgUDPAddrPort(buf, nil, daddr4in6) failed: %v", err)
   767  	}
   768  
   769  	if _, _, err = conn.WriteMsgUDPAddrPort(buf, nil, daddr6); err == nil {
   770  		t.Errorf("conn.WriteMsgUDPAddrPort(buf, nil, daddr6) should have failed, but got no error")
   771  	}
   772  }
   773  
   774  // TestReadWriteMsgUDPAddrPortEmptyCmsg verifies that ReadMsgUDPAddrPort and
   775  // WriteMsgUDPAddrPort won't fail when the cmsg buffer (the oob parameter) is
   776  // non-nil but empty.
   777  //
   778  // This is a regression test for https://golang.org/issue/77875.
   779  func TestReadWriteMsgUDPAddrPortEmptyCmsg(t *testing.T) {
   780  	switch runtime.GOOS {
   781  	case "plan9":
   782  		t.Skipf("not supported on %s", runtime.GOOS)
   783  	}
   784  
   785  	if !testableNetwork("udp4") {
   786  		t.Skipf("skipping: udp4 not available")
   787  	}
   788  
   789  	conn, err := ListenUDP("udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)})
   790  	if err != nil {
   791  		t.Fatal(err)
   792  	}
   793  	defer conn.Close()
   794  
   795  	buf := make([]byte, 8)
   796  	cmsgBuf := make([]byte, 8)[:0]
   797  	daddr := conn.LocalAddr().(*UDPAddr).AddrPort()
   798  
   799  	_, cmsgn, err := conn.WriteMsgUDPAddrPort(buf, cmsgBuf, daddr)
   800  	if err != nil {
   801  		t.Fatalf("WriteMsgUDPAddrPort failed: %v", err)
   802  	}
   803  	if cmsgn != 0 {
   804  		t.Errorf("WriteMsgUDPAddrPort wrote %d cmsg bytes; want 0", cmsgn)
   805  	}
   806  
   807  	_, cmsgn, _, _, err = conn.ReadMsgUDPAddrPort(buf, cmsgBuf)
   808  	if err != nil {
   809  		t.Fatalf("ReadMsgUDPAddrPort failed: %v", err)
   810  	}
   811  	if cmsgn != 0 {
   812  		t.Errorf("ReadMsgUDPAddrPort read %d cmsg bytes; want 0", cmsgn)
   813  	}
   814  }
   815  
   816  // TestDualStackUDPBroadcast verifies that a dual-stack UDP socket can send
   817  // a broadcast message to an IPv4 broadcast address.
   818  func TestDualStackUDPBroadcast(t *testing.T) {
   819  	switch runtime.GOOS {
   820  	case "plan9":
   821  		t.Skipf("not supported on %s", runtime.GOOS)
   822  	}
   823  	if !supportsIPv4map() {
   824  		t.Skip("dual-stack IPv6 sockets not supported")
   825  	}
   826  	mustHaveExternalNetwork(t)
   827  
   828  	conn, err := ListenUDP("udp", nil)
   829  	if err != nil {
   830  		t.Fatal(err)
   831  	}
   832  	defer conn.Close()
   833  
   834  	addr := netip.AddrPortFrom(netip.MustParseAddr("255.255.255.255"), 12345)
   835  	if _, err := conn.WriteToUDPAddrPort([]byte{0}, addr); err != nil {
   836  		if isUnreachableError(err) {
   837  			t.Skipf("broadcast route not available: %v", err)
   838  		}
   839  		t.Errorf("WriteToUDPAddrPort failed: %v", err)
   840  	}
   841  }
   842  

View as plain text