Source file src/net/ipsock_test.go

     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 net
     6  
     7  import (
     8  	"reflect"
     9  	"runtime"
    10  	"testing"
    11  )
    12  
    13  var testInetaddr = func(ip IPAddr) Addr { return &TCPAddr{IP: ip.IP, Port: 5682, Zone: ip.Zone} }
    14  
    15  var addrListTests = []struct {
    16  	filter    func(IPAddr) bool
    17  	ips       []IPAddr
    18  	inetaddr  func(IPAddr) Addr
    19  	first     Addr
    20  	primaries addrList
    21  	fallbacks addrList
    22  	err       error
    23  }{
    24  	{
    25  		nil,
    26  		[]IPAddr{
    27  			{IP: IPv4(127, 0, 0, 1)},
    28  			{IP: IPv6loopback},
    29  		},
    30  		testInetaddr,
    31  		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
    32  		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
    33  		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
    34  		nil,
    35  	},
    36  	{
    37  		nil,
    38  		[]IPAddr{
    39  			{IP: IPv6loopback},
    40  			{IP: IPv4(127, 0, 0, 1)},
    41  		},
    42  		testInetaddr,
    43  		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
    44  		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
    45  		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
    46  		nil,
    47  	},
    48  	{
    49  		nil,
    50  		[]IPAddr{
    51  			{IP: IPv4(127, 0, 0, 1)},
    52  			{IP: IPv4(192, 168, 0, 1)},
    53  		},
    54  		testInetaddr,
    55  		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
    56  		addrList{
    57  			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
    58  			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
    59  		},
    60  		nil,
    61  		nil,
    62  	},
    63  	{
    64  		nil,
    65  		[]IPAddr{
    66  			{IP: IPv6loopback},
    67  			{IP: ParseIP("fe80::1"), Zone: "eth0"},
    68  		},
    69  		testInetaddr,
    70  		&TCPAddr{IP: IPv6loopback, Port: 5682},
    71  		addrList{
    72  			&TCPAddr{IP: IPv6loopback, Port: 5682},
    73  			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
    74  		},
    75  		nil,
    76  		nil,
    77  	},
    78  	{
    79  		nil,
    80  		[]IPAddr{
    81  			{IP: IPv4(127, 0, 0, 1)},
    82  			{IP: IPv4(192, 168, 0, 1)},
    83  			{IP: IPv6loopback},
    84  			{IP: ParseIP("fe80::1"), Zone: "eth0"},
    85  		},
    86  		testInetaddr,
    87  		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
    88  		addrList{
    89  			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
    90  			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
    91  		},
    92  		addrList{
    93  			&TCPAddr{IP: IPv6loopback, Port: 5682},
    94  			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
    95  		},
    96  		nil,
    97  	},
    98  	{
    99  		nil,
   100  		[]IPAddr{
   101  			{IP: IPv6loopback},
   102  			{IP: ParseIP("fe80::1"), Zone: "eth0"},
   103  			{IP: IPv4(127, 0, 0, 1)},
   104  			{IP: IPv4(192, 168, 0, 1)},
   105  		},
   106  		testInetaddr,
   107  		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
   108  		addrList{
   109  			&TCPAddr{IP: IPv6loopback, Port: 5682},
   110  			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
   111  		},
   112  		addrList{
   113  			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
   114  			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
   115  		},
   116  		nil,
   117  	},
   118  	{
   119  		nil,
   120  		[]IPAddr{
   121  			{IP: IPv4(127, 0, 0, 1)},
   122  			{IP: IPv6loopback},
   123  			{IP: IPv4(192, 168, 0, 1)},
   124  			{IP: ParseIP("fe80::1"), Zone: "eth0"},
   125  		},
   126  		testInetaddr,
   127  		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
   128  		addrList{
   129  			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
   130  			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
   131  		},
   132  		addrList{
   133  			&TCPAddr{IP: IPv6loopback, Port: 5682},
   134  			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
   135  		},
   136  		nil,
   137  	},
   138  	{
   139  		nil,
   140  		[]IPAddr{
   141  			{IP: IPv6loopback},
   142  			{IP: IPv4(127, 0, 0, 1)},
   143  			{IP: ParseIP("fe80::1"), Zone: "eth0"},
   144  			{IP: IPv4(192, 168, 0, 1)},
   145  		},
   146  		testInetaddr,
   147  		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
   148  		addrList{
   149  			&TCPAddr{IP: IPv6loopback, Port: 5682},
   150  			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
   151  		},
   152  		addrList{
   153  			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
   154  			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
   155  		},
   156  		nil,
   157  	},
   158  
   159  	{
   160  		ipv4only,
   161  		[]IPAddr{
   162  			{IP: IPv4(127, 0, 0, 1)},
   163  			{IP: IPv6loopback},
   164  		},
   165  		testInetaddr,
   166  		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
   167  		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
   168  		nil,
   169  		nil,
   170  	},
   171  	{
   172  		ipv4only,
   173  		[]IPAddr{
   174  			{IP: IPv6loopback},
   175  			{IP: IPv4(127, 0, 0, 1)},
   176  		},
   177  		testInetaddr,
   178  		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
   179  		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
   180  		nil,
   181  		nil,
   182  	},
   183  
   184  	{
   185  		ipv6only,
   186  		[]IPAddr{
   187  			{IP: IPv4(127, 0, 0, 1)},
   188  			{IP: IPv6loopback},
   189  		},
   190  		testInetaddr,
   191  		&TCPAddr{IP: IPv6loopback, Port: 5682},
   192  		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
   193  		nil,
   194  		nil,
   195  	},
   196  	{
   197  		ipv6only,
   198  		[]IPAddr{
   199  			{IP: IPv6loopback},
   200  			{IP: IPv4(127, 0, 0, 1)},
   201  		},
   202  		testInetaddr,
   203  		&TCPAddr{IP: IPv6loopback, Port: 5682},
   204  		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
   205  		nil,
   206  		nil,
   207  	},
   208  
   209  	{nil, nil, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
   210  
   211  	{ipv4only, nil, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
   212  	{ipv4only, []IPAddr{{IP: IPv6loopback}}, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
   213  
   214  	{ipv6only, nil, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
   215  	{ipv6only, []IPAddr{{IP: IPv4(127, 0, 0, 1)}}, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
   216  }
   217  
   218  func TestAddrList(t *testing.T) {
   219  	if !supportsIPv4() || !supportsIPv6() {
   220  		t.Skip("both IPv4 and IPv6 are required")
   221  	}
   222  
   223  	for i, tt := range addrListTests {
   224  		addrs, err := filterAddrList(tt.filter, tt.ips, tt.inetaddr, "ADDR")
   225  		if !reflect.DeepEqual(err, tt.err) {
   226  			t.Errorf("#%v: got %v; want %v", i, err, tt.err)
   227  		}
   228  		if tt.err != nil {
   229  			if len(addrs) != 0 {
   230  				t.Errorf("#%v: got %v; want 0", i, len(addrs))
   231  			}
   232  			continue
   233  		}
   234  		first := addrs.first(isIPv4)
   235  		if !reflect.DeepEqual(first, tt.first) {
   236  			t.Errorf("#%v: got %v; want %v", i, first, tt.first)
   237  		}
   238  		primaries, fallbacks := addrs.partition(isIPv4)
   239  		if !reflect.DeepEqual(primaries, tt.primaries) {
   240  			t.Errorf("#%v: got %v; want %v", i, primaries, tt.primaries)
   241  		}
   242  		if !reflect.DeepEqual(fallbacks, tt.fallbacks) {
   243  			t.Errorf("#%v: got %v; want %v", i, fallbacks, tt.fallbacks)
   244  		}
   245  		expectedLen := len(primaries) + len(fallbacks)
   246  		if len(addrs) != expectedLen {
   247  			t.Errorf("#%v: got %v; want %v", i, len(addrs), expectedLen)
   248  		}
   249  	}
   250  }
   251  
   252  func TestAddrListPartition(t *testing.T) {
   253  	addrs := addrList{
   254  		&IPAddr{IP: ParseIP("fe80::"), Zone: "eth0"},
   255  		&IPAddr{IP: ParseIP("fe80::1"), Zone: "eth0"},
   256  		&IPAddr{IP: ParseIP("fe80::2"), Zone: "eth0"},
   257  	}
   258  	cases := []struct {
   259  		lastByte  byte
   260  		primaries addrList
   261  		fallbacks addrList
   262  	}{
   263  		{0, addrList{addrs[0]}, addrList{addrs[1], addrs[2]}},
   264  		{1, addrList{addrs[0], addrs[2]}, addrList{addrs[1]}},
   265  		{2, addrList{addrs[0], addrs[1]}, addrList{addrs[2]}},
   266  		{3, addrList{addrs[0], addrs[1], addrs[2]}, nil},
   267  	}
   268  	for i, tt := range cases {
   269  		// Inverting the function's output should not affect the outcome.
   270  		for _, invert := range []bool{false, true} {
   271  			primaries, fallbacks := addrs.partition(func(a Addr) bool {
   272  				ip := a.(*IPAddr).IP
   273  				return (ip[len(ip)-1] == tt.lastByte) != invert
   274  			})
   275  			if !reflect.DeepEqual(primaries, tt.primaries) {
   276  				t.Errorf("#%v: got %v; want %v", i, primaries, tt.primaries)
   277  			}
   278  			if !reflect.DeepEqual(fallbacks, tt.fallbacks) {
   279  				t.Errorf("#%v: got %v; want %v", i, fallbacks, tt.fallbacks)
   280  			}
   281  		}
   282  	}
   283  }
   284  
   285  func TestListenIPv6WildcardAddr(t *testing.T) {
   286  	if runtime.GOOS == "js" || runtime.GOOS == "wasip1" {
   287  		t.Skip("fake networking does not implement [::] wildcard address assertions")
   288  	}
   289  	if !supportsIPv6() {
   290  		t.Skip("IPv6 not supported")
   291  	}
   292  	if !supportsIPv4map() {
   293  		t.Skip("dual-stack IPv6 sockets not supported")
   294  	}
   295  
   296  	ln, err := Listen("tcp", "[::]:0")
   297  	if err != nil {
   298  		t.Fatal(err)
   299  	}
   300  	defer ln.Close()
   301  
   302  	addr := ln.Addr().(*TCPAddr)
   303  	if addr.IP.To4() != nil {
   304  		t.Errorf("Listen(\"tcp\", \"[::]:0\") bound to %v, want IPv6 address", addr)
   305  	}
   306  }
   307  

View as plain text