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