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 }