github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/net/ipv6/readwrite_test.go (about)

     1  // Copyright 2013 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 ipv6_test
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"net"
    11  	"runtime"
    12  	"strings"
    13  	"sync"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/hxx258456/ccgo/net/internal/iana"
    18  	"github.com/hxx258456/ccgo/net/ipv6"
    19  	"github.com/hxx258456/ccgo/net/nettest"
    20  )
    21  
    22  func BenchmarkReadWriteUnicast(b *testing.B) {
    23  	switch runtime.GOOS {
    24  	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
    25  		b.Skipf("not supported on %s", runtime.GOOS)
    26  	}
    27  
    28  	c, err := nettest.NewLocalPacketListener("udp6")
    29  	if err != nil {
    30  		b.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err)
    31  	}
    32  	defer c.Close()
    33  
    34  	dst := c.LocalAddr()
    35  	wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128)
    36  
    37  	b.Run("NetUDP", func(b *testing.B) {
    38  		for i := 0; i < b.N; i++ {
    39  			if _, err := c.WriteTo(wb, dst); err != nil {
    40  				b.Fatal(err)
    41  			}
    42  			if _, _, err := c.ReadFrom(rb); err != nil {
    43  				b.Fatal(err)
    44  			}
    45  		}
    46  	})
    47  	b.Run("IPv6UDP", func(b *testing.B) {
    48  		p := ipv6.NewPacketConn(c)
    49  		cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
    50  		if err := p.SetControlMessage(cf, true); err != nil {
    51  			b.Fatal(err)
    52  		}
    53  		cm := ipv6.ControlMessage{
    54  			TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced,
    55  			HopLimit:     1,
    56  		}
    57  		ifi, _ := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback)
    58  		if ifi != nil {
    59  			cm.IfIndex = ifi.Index
    60  		}
    61  
    62  		for i := 0; i < b.N; i++ {
    63  			if _, err := p.WriteTo(wb, &cm, dst); err != nil {
    64  				b.Fatal(err)
    65  			}
    66  			if _, _, _, err := p.ReadFrom(rb); err != nil {
    67  				b.Fatal(err)
    68  			}
    69  		}
    70  	})
    71  }
    72  
    73  func BenchmarkPacketConnReadWriteUnicast(b *testing.B) {
    74  	switch runtime.GOOS {
    75  	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
    76  		b.Skipf("not supported on %s", runtime.GOOS)
    77  	}
    78  
    79  	payload := []byte("HELLO-R-U-THERE")
    80  	iph := []byte{
    81  		0x69, 0x8b, 0xee, 0xf1, 0xca, 0xfe, 0xff, 0x01,
    82  		0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x00,
    83  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    84  		0x20, 0x01, 0x0d, 0xb8, 0x00, 0x02, 0x00, 0x00,
    85  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    86  	}
    87  	greh := []byte{0x00, 0x00, 0x86, 0xdd, 0x00, 0x00, 0x00, 0x00}
    88  	datagram := append(greh, append(iph, payload...)...)
    89  	bb := make([]byte, 128)
    90  	cm := ipv6.ControlMessage{
    91  		TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced,
    92  		HopLimit:     1,
    93  		Src:          net.IPv6loopback,
    94  	}
    95  	ifi, _ := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback)
    96  	if ifi != nil {
    97  		cm.IfIndex = ifi.Index
    98  	}
    99  
   100  	b.Run("UDP", func(b *testing.B) {
   101  		c, err := nettest.NewLocalPacketListener("udp6")
   102  		if err != nil {
   103  			b.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err)
   104  		}
   105  		defer c.Close()
   106  		p := ipv6.NewPacketConn(c)
   107  		dst := c.LocalAddr()
   108  		cf := ipv6.FlagHopLimit | ipv6.FlagInterface
   109  		if err := p.SetControlMessage(cf, true); err != nil {
   110  			b.Fatal(err)
   111  		}
   112  		wms := []ipv6.Message{
   113  			{
   114  				Buffers: [][]byte{payload},
   115  				Addr:    dst,
   116  				OOB:     cm.Marshal(),
   117  			},
   118  		}
   119  		rms := []ipv6.Message{
   120  			{
   121  				Buffers: [][]byte{bb},
   122  				OOB:     ipv6.NewControlMessage(cf),
   123  			},
   124  		}
   125  		b.Run("Net", func(b *testing.B) {
   126  			for i := 0; i < b.N; i++ {
   127  				if _, err := c.WriteTo(payload, dst); err != nil {
   128  					b.Fatal(err)
   129  				}
   130  				if _, _, err := c.ReadFrom(bb); err != nil {
   131  					b.Fatal(err)
   132  				}
   133  			}
   134  		})
   135  		b.Run("ToFrom", func(b *testing.B) {
   136  			for i := 0; i < b.N; i++ {
   137  				if _, err := p.WriteTo(payload, &cm, dst); err != nil {
   138  					b.Fatal(err)
   139  				}
   140  				if _, _, _, err := p.ReadFrom(bb); err != nil {
   141  					b.Fatal(err)
   142  				}
   143  			}
   144  		})
   145  		b.Run("Batch", func(b *testing.B) {
   146  			for i := 0; i < b.N; i++ {
   147  				if _, err := p.WriteBatch(wms, 0); err != nil {
   148  					b.Fatal(err)
   149  				}
   150  				if _, err := p.ReadBatch(rms, 0); err != nil {
   151  					b.Fatal(err)
   152  				}
   153  			}
   154  		})
   155  	})
   156  	b.Run("IP", func(b *testing.B) {
   157  		switch runtime.GOOS {
   158  		case "netbsd":
   159  			b.Skip("need to configure gre on netbsd")
   160  		case "openbsd":
   161  			b.Skip("net.inet.gre.allow=0 by default on openbsd")
   162  		}
   163  
   164  		c, err := net.ListenPacket(fmt.Sprintf("ip6:%d", iana.ProtocolGRE), "::1")
   165  		if err != nil {
   166  			b.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err)
   167  		}
   168  		defer c.Close()
   169  		p := ipv6.NewPacketConn(c)
   170  		dst := c.LocalAddr()
   171  		cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
   172  		if err := p.SetControlMessage(cf, true); err != nil {
   173  			b.Fatal(err)
   174  		}
   175  		wms := []ipv6.Message{
   176  			{
   177  				Buffers: [][]byte{datagram},
   178  				Addr:    dst,
   179  				OOB:     cm.Marshal(),
   180  			},
   181  		}
   182  		rms := []ipv6.Message{
   183  			{
   184  				Buffers: [][]byte{bb},
   185  				OOB:     ipv6.NewControlMessage(cf),
   186  			},
   187  		}
   188  		b.Run("Net", func(b *testing.B) {
   189  			for i := 0; i < b.N; i++ {
   190  				if _, err := c.WriteTo(datagram, dst); err != nil {
   191  					b.Fatal(err)
   192  				}
   193  				if _, _, err := c.ReadFrom(bb); err != nil {
   194  					b.Fatal(err)
   195  				}
   196  			}
   197  		})
   198  		b.Run("ToFrom", func(b *testing.B) {
   199  			for i := 0; i < b.N; i++ {
   200  				if _, err := p.WriteTo(datagram, &cm, dst); err != nil {
   201  					b.Fatal(err)
   202  				}
   203  				if _, _, _, err := p.ReadFrom(bb); err != nil {
   204  					b.Fatal(err)
   205  				}
   206  			}
   207  		})
   208  		b.Run("Batch", func(b *testing.B) {
   209  			for i := 0; i < b.N; i++ {
   210  				if _, err := p.WriteBatch(wms, 0); err != nil {
   211  					b.Fatal(err)
   212  				}
   213  				if _, err := p.ReadBatch(rms, 0); err != nil {
   214  					b.Fatal(err)
   215  				}
   216  			}
   217  		})
   218  	})
   219  }
   220  
   221  func TestPacketConnConcurrentReadWriteUnicastUDP(t *testing.T) {
   222  	switch runtime.GOOS {
   223  	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
   224  		t.Skipf("not supported on %s", runtime.GOOS)
   225  	}
   226  	if !nettest.SupportsIPv6() {
   227  		t.Skip("ipv6 is not supported")
   228  	}
   229  
   230  	c, err := nettest.NewLocalPacketListener("udp6")
   231  	if err != nil {
   232  		t.Fatal(err)
   233  	}
   234  	defer c.Close()
   235  	p := ipv6.NewPacketConn(c)
   236  	defer p.Close()
   237  
   238  	dst := c.LocalAddr()
   239  	ifi, _ := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback)
   240  	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
   241  	wb := []byte("HELLO-R-U-THERE")
   242  
   243  	if err := p.SetControlMessage(cf, true); err != nil { // probe before test
   244  		if protocolNotSupported(err) {
   245  			t.Skipf("not supported on %s", runtime.GOOS)
   246  		}
   247  		t.Fatal(err)
   248  	}
   249  
   250  	var wg sync.WaitGroup
   251  	reader := func() {
   252  		defer wg.Done()
   253  		rb := make([]byte, 128)
   254  		if n, cm, _, err := p.ReadFrom(rb); err != nil {
   255  			t.Error(err)
   256  			return
   257  		} else if !bytes.Equal(rb[:n], wb) {
   258  			t.Errorf("got %v; want %v", rb[:n], wb)
   259  			return
   260  		} else {
   261  			s := cm.String()
   262  			if strings.Contains(s, ",") {
   263  				t.Errorf("should be space-separated values: %s", s)
   264  			}
   265  		}
   266  	}
   267  	writer := func(toggle bool) {
   268  		defer wg.Done()
   269  		cm := ipv6.ControlMessage{
   270  			TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced,
   271  			Src:          net.IPv6loopback,
   272  		}
   273  		if ifi != nil {
   274  			cm.IfIndex = ifi.Index
   275  		}
   276  		if err := p.SetControlMessage(cf, toggle); err != nil {
   277  			t.Error(err)
   278  			return
   279  		}
   280  		if n, err := p.WriteTo(wb, &cm, dst); err != nil {
   281  			t.Error(err)
   282  			return
   283  		} else if n != len(wb) {
   284  			t.Errorf("got %d; want %d", n, len(wb))
   285  			return
   286  		}
   287  	}
   288  
   289  	const N = 10
   290  	wg.Add(N)
   291  	for i := 0; i < N; i++ {
   292  		go reader()
   293  	}
   294  	wg.Add(2 * N)
   295  	for i := 0; i < 2*N; i++ {
   296  		go writer(i%2 != 0)
   297  	}
   298  	wg.Add(N)
   299  	for i := 0; i < N; i++ {
   300  		go reader()
   301  	}
   302  	wg.Wait()
   303  }
   304  
   305  func TestPacketConnConcurrentReadWriteUnicast(t *testing.T) {
   306  	switch runtime.GOOS {
   307  	case "fuchsia", "hurd", "js", "nacl", "plan9", "windows":
   308  		t.Skipf("not supported on %s", runtime.GOOS)
   309  	}
   310  
   311  	payload := []byte("HELLO-R-U-THERE")
   312  	iph := []byte{
   313  		0x69, 0x8b, 0xee, 0xf1, 0xca, 0xfe, 0xff, 0x01,
   314  		0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x00,
   315  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
   316  		0x20, 0x01, 0x0d, 0xb8, 0x00, 0x02, 0x00, 0x00,
   317  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
   318  	}
   319  	greh := []byte{0x00, 0x00, 0x86, 0xdd, 0x00, 0x00, 0x00, 0x00}
   320  	datagram := append(greh, append(iph, payload...)...)
   321  
   322  	t.Run("UDP", func(t *testing.T) {
   323  		c, err := nettest.NewLocalPacketListener("udp6")
   324  		if err != nil {
   325  			t.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err)
   326  		}
   327  		defer c.Close()
   328  		p := ipv6.NewPacketConn(c)
   329  		t.Run("ToFrom", func(t *testing.T) {
   330  			testPacketConnConcurrentReadWriteUnicast(t, p, payload, c.LocalAddr(), false)
   331  		})
   332  		t.Run("Batch", func(t *testing.T) {
   333  			testPacketConnConcurrentReadWriteUnicast(t, p, payload, c.LocalAddr(), true)
   334  		})
   335  	})
   336  	t.Run("IP", func(t *testing.T) {
   337  		switch runtime.GOOS {
   338  		case "netbsd":
   339  			t.Skip("need to configure gre on netbsd")
   340  		case "openbsd":
   341  			t.Skip("net.inet.gre.allow=0 by default on openbsd")
   342  		}
   343  
   344  		c, err := net.ListenPacket(fmt.Sprintf("ip6:%d", iana.ProtocolGRE), "::1")
   345  		if err != nil {
   346  			t.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err)
   347  		}
   348  		defer c.Close()
   349  		p := ipv6.NewPacketConn(c)
   350  		t.Run("ToFrom", func(t *testing.T) {
   351  			testPacketConnConcurrentReadWriteUnicast(t, p, datagram, c.LocalAddr(), false)
   352  		})
   353  		t.Run("Batch", func(t *testing.T) {
   354  			testPacketConnConcurrentReadWriteUnicast(t, p, datagram, c.LocalAddr(), true)
   355  		})
   356  	})
   357  }
   358  
   359  func testPacketConnConcurrentReadWriteUnicast(t *testing.T, p *ipv6.PacketConn, data []byte, dst net.Addr, batch bool) {
   360  	ifi, _ := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback)
   361  	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
   362  
   363  	if err := p.SetControlMessage(cf, true); err != nil { // probe before test
   364  		if protocolNotSupported(err) {
   365  			t.Skipf("not supported on %s", runtime.GOOS)
   366  		}
   367  		t.Fatal(err)
   368  	}
   369  
   370  	var firstError sync.Once
   371  	fatalf := func(format string, args ...interface{}) {
   372  		// On the first error, close the PacketConn to unblock the remaining
   373  		// goroutines. Suppress any further errors, which may occur simply due to
   374  		// closing the PacketConn.
   375  		first := false
   376  		firstError.Do(func() {
   377  			first = true
   378  			p.Close()
   379  		})
   380  		if first {
   381  			t.Helper()
   382  			t.Errorf(format, args...)
   383  		}
   384  		runtime.Goexit()
   385  	}
   386  
   387  	var wg sync.WaitGroup
   388  	reader := func() {
   389  		defer wg.Done()
   390  		b := make([]byte, 128)
   391  		n, cm, _, err := p.ReadFrom(b)
   392  		if err != nil {
   393  			fatalf("%v", err)
   394  		}
   395  		if !bytes.Equal(b[:n], data) {
   396  			fatalf("got %#v; want %#v", b[:n], data)
   397  		}
   398  		s := cm.String()
   399  		if strings.Contains(s, ",") {
   400  			fatalf("should be space-separated values: %s", s)
   401  		}
   402  	}
   403  	batchReader := func() {
   404  		defer wg.Done()
   405  		ms := []ipv6.Message{
   406  			{
   407  				Buffers: [][]byte{make([]byte, 128)},
   408  				OOB:     ipv6.NewControlMessage(cf),
   409  			},
   410  		}
   411  		n, err := p.ReadBatch(ms, 0)
   412  		if err != nil {
   413  			fatalf("%v", err)
   414  		}
   415  		if n != len(ms) {
   416  			fatalf("got %d; want %d", n, len(ms))
   417  		}
   418  		var cm ipv6.ControlMessage
   419  		if err := cm.Parse(ms[0].OOB[:ms[0].NN]); err != nil {
   420  			fatalf("%v", err)
   421  		}
   422  		b := ms[0].Buffers[0][:ms[0].N]
   423  		if !bytes.Equal(b, data) {
   424  			fatalf("got %#v; want %#v", b, data)
   425  		}
   426  		s := cm.String()
   427  		if strings.Contains(s, ",") {
   428  			fatalf("should be space-separated values: %s", s)
   429  		}
   430  	}
   431  	writer := func(toggle bool) {
   432  		defer wg.Done()
   433  		cm := ipv6.ControlMessage{
   434  			TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced,
   435  			HopLimit:     1,
   436  			Src:          net.IPv6loopback,
   437  		}
   438  		if ifi != nil {
   439  			cm.IfIndex = ifi.Index
   440  		}
   441  		if err := p.SetControlMessage(cf, toggle); err != nil {
   442  			fatalf("%v", err)
   443  		}
   444  
   445  		backoff := time.Millisecond
   446  		for {
   447  			n, err := p.WriteTo(data, &cm, dst)
   448  			if err != nil {
   449  				if n == 0 && isENOBUFS(err) {
   450  					time.Sleep(backoff)
   451  					backoff *= 2
   452  					continue
   453  				}
   454  				fatalf("%v", err)
   455  			}
   456  			if n != len(data) {
   457  				fatalf("got %d; want %d", n, len(data))
   458  			}
   459  			break
   460  		}
   461  	}
   462  	batchWriter := func(toggle bool) {
   463  		defer wg.Done()
   464  		cm := ipv6.ControlMessage{
   465  			TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced,
   466  			HopLimit:     1,
   467  			Src:          net.IPv6loopback,
   468  		}
   469  		if ifi != nil {
   470  			cm.IfIndex = ifi.Index
   471  		}
   472  		if err := p.SetControlMessage(cf, toggle); err != nil {
   473  			fatalf("%v", err)
   474  		}
   475  		ms := []ipv6.Message{
   476  			{
   477  				Buffers: [][]byte{data},
   478  				OOB:     cm.Marshal(),
   479  				Addr:    dst,
   480  			},
   481  		}
   482  
   483  		backoff := time.Millisecond
   484  		for {
   485  			n, err := p.WriteBatch(ms, 0)
   486  			if err != nil {
   487  				if n == 0 && isENOBUFS(err) {
   488  					time.Sleep(backoff)
   489  					backoff *= 2
   490  					continue
   491  				}
   492  				fatalf("%v", err)
   493  			}
   494  			if n != len(ms) {
   495  				fatalf("got %d; want %d", n, len(ms))
   496  			}
   497  			if ms[0].N != len(data) {
   498  				fatalf("got %d; want %d", ms[0].N, len(data))
   499  			}
   500  			break
   501  		}
   502  	}
   503  
   504  	const N = 10
   505  	wg.Add(N)
   506  	for i := 0; i < N; i++ {
   507  		if batch {
   508  			go batchReader()
   509  		} else {
   510  			go reader()
   511  		}
   512  	}
   513  	wg.Add(2 * N)
   514  	for i := 0; i < 2*N; i++ {
   515  		if batch {
   516  			go batchWriter(i%2 != 0)
   517  		} else {
   518  			go writer(i%2 != 0)
   519  		}
   520  	}
   521  	wg.Add(N)
   522  	for i := 0; i < N; i++ {
   523  		if batch {
   524  			go batchReader()
   525  		} else {
   526  			go reader()
   527  		}
   528  	}
   529  	wg.Wait()
   530  }