Home | History | Annotate | Download | only in net
      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 	"internal/testenv"
      9 	"reflect"
     10 	"runtime"
     11 	"testing"
     12 	"time"
     13 )
     14 
     15 func BenchmarkUDP6LinkLocalUnicast(b *testing.B) {
     16 	testHookUninstaller.Do(uninstallTestHooks)
     17 
     18 	if !supportsIPv6() {
     19 		b.Skip("IPv6 is not supported")
     20 	}
     21 	ifi := loopbackInterface()
     22 	if ifi == nil {
     23 		b.Skip("loopback interface not found")
     24 	}
     25 	lla := ipv6LinkLocalUnicastAddr(ifi)
     26 	if lla == "" {
     27 		b.Skip("IPv6 link-local unicast address not found")
     28 	}
     29 
     30 	c1, err := ListenPacket("udp6", JoinHostPort(lla+"%"+ifi.Name, "0"))
     31 	if err != nil {
     32 		b.Fatal(err)
     33 	}
     34 	defer c1.Close()
     35 	c2, err := ListenPacket("udp6", JoinHostPort(lla+"%"+ifi.Name, "0"))
     36 	if err != nil {
     37 		b.Fatal(err)
     38 	}
     39 	defer c2.Close()
     40 
     41 	var buf [1]byte
     42 	for i := 0; i < b.N; i++ {
     43 		if _, err := c1.WriteTo(buf[:], c2.LocalAddr()); err != nil {
     44 			b.Fatal(err)
     45 		}
     46 		if _, _, err := c2.ReadFrom(buf[:]); err != nil {
     47 			b.Fatal(err)
     48 		}
     49 	}
     50 }
     51 
     52 type resolveUDPAddrTest struct {
     53 	network       string
     54 	litAddrOrName string
     55 	addr          *UDPAddr
     56 	err           error
     57 }
     58 
     59 var resolveUDPAddrTests = []resolveUDPAddrTest{
     60 	{"udp", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
     61 	{"udp4", "127.0.0.1:65535", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
     62 
     63 	{"udp", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},
     64 	{"udp6", "[::1]:65535", &UDPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
     65 
     66 	{"udp", "[::1%en0]:1", &UDPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
     67 	{"udp6", "[::1%911]:2", &UDPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
     68 
     69 	{"", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
     70 	{"", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},         // Go 1.0 behavior
     71 
     72 	{"udp", ":12345", &UDPAddr{Port: 12345}, nil},
     73 
     74 	{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
     75 
     76 	{"udp", "127.0.0.1:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
     77 	{"udp", "[::ffff:127.0.0.1]:domain", &UDPAddr{IP: ParseIP("::ffff:127.0.0.1"), Port: 53}, nil},
     78 	{"udp", "[2001:db8::1]:domain", &UDPAddr{IP: ParseIP("2001:db8::1"), Port: 53}, nil},
     79 	{"udp4", "127.0.0.1:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
     80 	{"udp4", "[::ffff:127.0.0.1]:domain", &UDPAddr{IP: ParseIP("127.0.0.1"), Port: 53}, nil},
     81 	{"udp6", "[2001:db8::1]:domain", &UDPAddr{IP: ParseIP("2001:db8::1"), Port: 53}, nil},
     82 
     83 	{"udp4", "[2001:db8::1]:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "2001:db8::1"}},
     84 	{"udp6", "127.0.0.1:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "127.0.0.1"}},
     85 	{"udp6", "[::ffff:127.0.0.1]:domain", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "::ffff:127.0.0.1"}},
     86 }
     87 
     88 func TestResolveUDPAddr(t *testing.T) {
     89 	origTestHookLookupIP := testHookLookupIP
     90 	defer func() { testHookLookupIP = origTestHookLookupIP }()
     91 	testHookLookupIP = lookupLocalhost
     92 
     93 	for _, tt := range resolveUDPAddrTests {
     94 		addr, err := ResolveUDPAddr(tt.network, tt.litAddrOrName)
     95 		if !reflect.DeepEqual(addr, tt.addr) || !reflect.DeepEqual(err, tt.err) {
     96 			t.Errorf("ResolveUDPAddr(%q, %q) = %#v, %v, want %#v, %v", tt.network, tt.litAddrOrName, addr, err, tt.addr, tt.err)
     97 			continue
     98 		}
     99 		if err == nil {
    100 			addr2, err := ResolveUDPAddr(addr.Network(), addr.String())
    101 			if !reflect.DeepEqual(addr2, tt.addr) || err != tt.err {
    102 				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)
    103 			}
    104 		}
    105 	}
    106 }
    107 
    108 func TestWriteToUDP(t *testing.T) {
    109 	switch runtime.GOOS {
    110 	case "plan9":
    111 		t.Skipf("not supported on %s", runtime.GOOS)
    112 	}
    113 
    114 	c, err := ListenPacket("udp", "127.0.0.1:0")
    115 	if err != nil {
    116 		t.Fatal(err)
    117 	}
    118 	defer c.Close()
    119 
    120 	testWriteToConn(t, c.LocalAddr().String())
    121 	testWriteToPacketConn(t, c.LocalAddr().String())
    122 }
    123 
    124 func testWriteToConn(t *testing.T, raddr string) {
    125 	c, err := Dial("udp", raddr)
    126 	if err != nil {
    127 		t.Fatal(err)
    128 	}
    129 	defer c.Close()
    130 
    131 	ra, err := ResolveUDPAddr("udp", raddr)
    132 	if err != nil {
    133 		t.Fatal(err)
    134 	}
    135 
    136 	b := []byte("CONNECTED-MODE SOCKET")
    137 	_, err = c.(*UDPConn).WriteToUDP(b, ra)
    138 	if err == nil {
    139 		t.Fatal("should fail")
    140 	}
    141 	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
    142 		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
    143 	}
    144 	_, err = c.(*UDPConn).WriteTo(b, ra)
    145 	if err == nil {
    146 		t.Fatal("should fail")
    147 	}
    148 	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
    149 		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
    150 	}
    151 	_, err = c.Write(b)
    152 	if err != nil {
    153 		t.Fatal(err)
    154 	}
    155 	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra)
    156 	if err == nil {
    157 		t.Fatal("should fail")
    158 	}
    159 	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
    160 		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
    161 	}
    162 	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
    163 	switch runtime.GOOS {
    164 	case "nacl": // see golang.org/issue/9252
    165 		t.Skipf("not implemented yet on %s", runtime.GOOS)
    166 	case "windows":
    167 		if testenv.IsWindowsXP() {
    168 			t.Log("skipping broken test on Windows XP (see golang.org/issue/23072)")
    169 			return
    170 		}
    171 	default:
    172 		if err != nil {
    173 			t.Fatal(err)
    174 		}
    175 	}
    176 }
    177 
    178 func testWriteToPacketConn(t *testing.T, raddr string) {
    179 	c, err := ListenPacket("udp", "127.0.0.1:0")
    180 	if err != nil {
    181 		t.Fatal(err)
    182 	}
    183 	defer c.Close()
    184 
    185 	ra, err := ResolveUDPAddr("udp", raddr)
    186 	if err != nil {
    187 		t.Fatal(err)
    188 	}
    189 
    190 	b := []byte("UNCONNECTED-MODE SOCKET")
    191 	_, err = c.(*UDPConn).WriteToUDP(b, ra)
    192 	if err != nil {
    193 		t.Fatal(err)
    194 	}
    195 	_, err = c.WriteTo(b, ra)
    196 	if err != nil {
    197 		t.Fatal(err)
    198 	}
    199 	_, err = c.(*UDPConn).Write(b)
    200 	if err == nil {
    201 		t.Fatal("should fail")
    202 	}
    203 	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
    204 	if err == nil {
    205 		t.Fatal("should fail")
    206 	}
    207 	if err != nil && err.(*OpError).Err != errMissingAddress {
    208 		t.Fatalf("should fail as errMissingAddress: %v", err)
    209 	}
    210 	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra)
    211 	switch runtime.GOOS {
    212 	case "nacl": // see golang.org/issue/9252
    213 		t.Skipf("not implemented yet on %s", runtime.GOOS)
    214 	case "windows":
    215 		if testenv.IsWindowsXP() {
    216 			t.Log("skipping broken test on Windows XP (see golang.org/issue/23072)")
    217 			return
    218 		}
    219 	default:
    220 		if err != nil {
    221 			t.Fatal(err)
    222 		}
    223 	}
    224 }
    225 
    226 var udpConnLocalNameTests = []struct {
    227 	net   string
    228 	laddr *UDPAddr
    229 }{
    230 	{"udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)}},
    231 	{"udp4", &UDPAddr{}},
    232 	{"udp4", nil},
    233 }
    234 
    235 func TestUDPConnLocalName(t *testing.T) {
    236 	testenv.MustHaveExternalNetwork(t)
    237 
    238 	for _, tt := range udpConnLocalNameTests {
    239 		c, err := ListenUDP(tt.net, tt.laddr)
    240 		if err != nil {
    241 			t.Fatal(err)
    242 		}
    243 		defer c.Close()
    244 		la := c.LocalAddr()
    245 		if a, ok := la.(*UDPAddr); !ok || a.Port == 0 {
    246 			t.Fatalf("got %v; expected a proper address with non-zero port number", la)
    247 		}
    248 	}
    249 }
    250 
    251 func TestUDPConnLocalAndRemoteNames(t *testing.T) {
    252 	for _, laddr := range []string{"", "127.0.0.1:0"} {
    253 		c1, err := ListenPacket("udp", "127.0.0.1:0")
    254 		if err != nil {
    255 			t.Fatal(err)
    256 		}
    257 		defer c1.Close()
    258 
    259 		var la *UDPAddr
    260 		if laddr != "" {
    261 			var err error
    262 			if la, err = ResolveUDPAddr("udp", laddr); err != nil {
    263 				t.Fatal(err)
    264 			}
    265 		}
    266 		c2, err := DialUDP("udp", la, c1.LocalAddr().(*UDPAddr))
    267 		if err != nil {
    268 			t.Fatal(err)
    269 		}
    270 		defer c2.Close()
    271 
    272 		var connAddrs = [4]struct {
    273 			got Addr
    274 			ok  bool
    275 		}{
    276 			{c1.LocalAddr(), true},
    277 			{c1.(*UDPConn).RemoteAddr(), false},
    278 			{c2.LocalAddr(), true},
    279 			{c2.RemoteAddr(), true},
    280 		}
    281 		for _, ca := range connAddrs {
    282 			if a, ok := ca.got.(*UDPAddr); ok != ca.ok || ok && a.Port == 0 {
    283 				t.Fatalf("got %v; expected a proper address with non-zero port number", ca.got)
    284 			}
    285 		}
    286 	}
    287 }
    288 
    289 func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
    290 	testenv.MustHaveExternalNetwork(t)
    291 
    292 	if !supportsIPv6() {
    293 		t.Skip("IPv6 is not supported")
    294 	}
    295 
    296 	for i, tt := range ipv6LinkLocalUnicastUDPTests {
    297 		c1, err := ListenPacket(tt.network, tt.address)
    298 		if err != nil {
    299 			// It might return "LookupHost returned no
    300 			// suitable address" error on some platforms.
    301 			t.Log(err)
    302 			continue
    303 		}
    304 		ls, err := (&packetListener{PacketConn: c1}).newLocalServer()
    305 		if err != nil {
    306 			t.Fatal(err)
    307 		}
    308 		defer ls.teardown()
    309 		ch := make(chan error, 1)
    310 		handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, ch) }
    311 		if err := ls.buildup(handler); err != nil {
    312 			t.Fatal(err)
    313 		}
    314 		if la, ok := c1.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
    315 			t.Fatalf("got %v; expected a proper address with zone identifier", la)
    316 		}
    317 
    318 		c2, err := Dial(tt.network, ls.PacketConn.LocalAddr().String())
    319 		if err != nil {
    320 			t.Fatal(err)
    321 		}
    322 		defer c2.Close()
    323 		if la, ok := c2.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
    324 			t.Fatalf("got %v; expected a proper address with zone identifier", la)
    325 		}
    326 		if ra, ok := c2.RemoteAddr().(*UDPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
    327 			t.Fatalf("got %v; expected a proper address with zone identifier", ra)
    328 		}
    329 
    330 		if _, err := c2.Write([]byte("UDP OVER IPV6 LINKLOCAL TEST")); err != nil {
    331 			t.Fatal(err)
    332 		}
    333 		b := make([]byte, 32)
    334 		if _, err := c2.Read(b); err != nil {
    335 			t.Fatal(err)
    336 		}
    337 
    338 		for err := range ch {
    339 			t.Errorf("#%d: %v", i, err)
    340 		}
    341 	}
    342 }
    343 
    344 func TestUDPZeroBytePayload(t *testing.T) {
    345 	switch runtime.GOOS {
    346 	case "nacl", "plan9":
    347 		t.Skipf("not supported on %s", runtime.GOOS)
    348 	}
    349 
    350 	c, err := newLocalPacketListener("udp")
    351 	if err != nil {
    352 		t.Fatal(err)
    353 	}
    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(100 * time.Millisecond))
    365 		var b [1]byte
    366 		if genericRead {
    367 			_, err = c.(Conn).Read(b[:])
    368 		} else {
    369 			_, _, err = c.ReadFrom(b[:])
    370 		}
    371 		switch err {
    372 		case nil: // ReadFrom succeeds
    373 		default: // Read may timeout, it depends on the platform
    374 			if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
    375 				t.Fatal(err)
    376 			}
    377 		}
    378 	}
    379 }
    380 
    381 func TestUDPZeroByteBuffer(t *testing.T) {
    382 	switch runtime.GOOS {
    383 	case "nacl", "plan9":
    384 		t.Skipf("not supported on %s", runtime.GOOS)
    385 	}
    386 
    387 	c, err := newLocalPacketListener("udp")
    388 	if err != nil {
    389 		t.Fatal(err)
    390 	}
    391 	defer c.Close()
    392 
    393 	b := []byte("UDP ZERO BYTE BUFFER TEST")
    394 	for _, genericRead := range []bool{false, true} {
    395 		n, err := c.WriteTo(b, c.LocalAddr())
    396 		if err != nil {
    397 			t.Fatal(err)
    398 		}
    399 		if n != len(b) {
    400 			t.Errorf("got %d; want %d", n, len(b))
    401 		}
    402 		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
    403 		if genericRead {
    404 			_, err = c.(Conn).Read(nil)
    405 		} else {
    406 			_, _, err = c.ReadFrom(nil)
    407 		}
    408 		switch err {
    409 		case nil: // ReadFrom succeeds
    410 		default: // Read may timeout, it depends on the platform
    411 			if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZ
    412 				t.Fatal(err)
    413 			}
    414 		}
    415 	}
    416 }
    417