| // Copyright 2011 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | // +build !js | 
 |  | 
 | package net | 
 |  | 
 | import ( | 
 | 	"os" | 
 | 	"reflect" | 
 | 	"runtime" | 
 | 	"sync" | 
 | 	"testing" | 
 | ) | 
 |  | 
 | // The full stack test cases for IPConn have been moved to the | 
 | // following: | 
 | //      golang.org/x/net/ipv4 | 
 | //      golang.org/x/net/ipv6 | 
 | //      golang.org/x/net/icmp | 
 |  | 
 | var fileConnTests = []struct { | 
 | 	network string | 
 | }{ | 
 | 	{"tcp"}, | 
 | 	{"udp"}, | 
 | 	{"unix"}, | 
 | 	{"unixpacket"}, | 
 | } | 
 |  | 
 | func TestFileConn(t *testing.T) { | 
 | 	switch runtime.GOOS { | 
 | 	case "plan9", "windows": | 
 | 		t.Skipf("not supported on %s", runtime.GOOS) | 
 | 	} | 
 |  | 
 | 	for _, tt := range fileConnTests { | 
 | 		if !testableNetwork(tt.network) { | 
 | 			t.Logf("skipping %s test", tt.network) | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		var network, address string | 
 | 		switch tt.network { | 
 | 		case "udp": | 
 | 			c, err := newLocalPacketListener(tt.network) | 
 | 			if err != nil { | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			defer c.Close() | 
 | 			network = c.LocalAddr().Network() | 
 | 			address = c.LocalAddr().String() | 
 | 		default: | 
 | 			handler := func(ls *localServer, ln Listener) { | 
 | 				c, err := ln.Accept() | 
 | 				if err != nil { | 
 | 					return | 
 | 				} | 
 | 				defer c.Close() | 
 | 				var b [1]byte | 
 | 				c.Read(b[:]) | 
 | 			} | 
 | 			ls, err := newLocalServer(tt.network) | 
 | 			if err != nil { | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			defer ls.teardown() | 
 | 			if err := ls.buildup(handler); err != nil { | 
 | 				t.Fatal(err) | 
 | 			} | 
 | 			network = ls.Listener.Addr().Network() | 
 | 			address = ls.Listener.Addr().String() | 
 | 		} | 
 |  | 
 | 		c1, err := Dial(network, address) | 
 | 		if err != nil { | 
 | 			if perr := parseDialError(err); perr != nil { | 
 | 				t.Error(perr) | 
 | 			} | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		addr := c1.LocalAddr() | 
 |  | 
 | 		var f *os.File | 
 | 		switch c1 := c1.(type) { | 
 | 		case *TCPConn: | 
 | 			f, err = c1.File() | 
 | 		case *UDPConn: | 
 | 			f, err = c1.File() | 
 | 		case *UnixConn: | 
 | 			f, err = c1.File() | 
 | 		} | 
 | 		if err := c1.Close(); err != nil { | 
 | 			if perr := parseCloseError(err, false); perr != nil { | 
 | 				t.Error(perr) | 
 | 			} | 
 | 			t.Error(err) | 
 | 		} | 
 | 		if err != nil { | 
 | 			if perr := parseCommonError(err); perr != nil { | 
 | 				t.Error(perr) | 
 | 			} | 
 | 			t.Fatal(err) | 
 | 		} | 
 |  | 
 | 		c2, err := FileConn(f) | 
 | 		if err := f.Close(); err != nil { | 
 | 			t.Error(err) | 
 | 		} | 
 | 		if err != nil { | 
 | 			if perr := parseCommonError(err); perr != nil { | 
 | 				t.Error(perr) | 
 | 			} | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		defer c2.Close() | 
 |  | 
 | 		if _, err := c2.Write([]byte("FILECONN TEST")); err != nil { | 
 | 			if perr := parseWriteError(err); perr != nil { | 
 | 				t.Error(perr) | 
 | 			} | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		if !reflect.DeepEqual(c2.LocalAddr(), addr) { | 
 | 			t.Fatalf("got %#v; want %#v", c2.LocalAddr(), addr) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | var fileListenerTests = []struct { | 
 | 	network string | 
 | }{ | 
 | 	{"tcp"}, | 
 | 	{"unix"}, | 
 | 	{"unixpacket"}, | 
 | } | 
 |  | 
 | func TestFileListener(t *testing.T) { | 
 | 	switch runtime.GOOS { | 
 | 	case "plan9", "windows": | 
 | 		t.Skipf("not supported on %s", runtime.GOOS) | 
 | 	} | 
 |  | 
 | 	for _, tt := range fileListenerTests { | 
 | 		if !testableNetwork(tt.network) { | 
 | 			t.Logf("skipping %s test", tt.network) | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		ln1, err := newLocalListener(tt.network) | 
 | 		if err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		switch tt.network { | 
 | 		case "unix", "unixpacket": | 
 | 			defer os.Remove(ln1.Addr().String()) | 
 | 		} | 
 | 		addr := ln1.Addr() | 
 |  | 
 | 		var f *os.File | 
 | 		switch ln1 := ln1.(type) { | 
 | 		case *TCPListener: | 
 | 			f, err = ln1.File() | 
 | 		case *UnixListener: | 
 | 			f, err = ln1.File() | 
 | 		} | 
 | 		switch tt.network { | 
 | 		case "unix", "unixpacket": | 
 | 			defer ln1.Close() // UnixListener.Close calls syscall.Unlink internally | 
 | 		default: | 
 | 			if err := ln1.Close(); err != nil { | 
 | 				t.Error(err) | 
 | 			} | 
 | 		} | 
 | 		if err != nil { | 
 | 			if perr := parseCommonError(err); perr != nil { | 
 | 				t.Error(perr) | 
 | 			} | 
 | 			t.Fatal(err) | 
 | 		} | 
 |  | 
 | 		ln2, err := FileListener(f) | 
 | 		if err := f.Close(); err != nil { | 
 | 			t.Error(err) | 
 | 		} | 
 | 		if err != nil { | 
 | 			if perr := parseCommonError(err); perr != nil { | 
 | 				t.Error(perr) | 
 | 			} | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		defer ln2.Close() | 
 |  | 
 | 		var wg sync.WaitGroup | 
 | 		wg.Add(1) | 
 | 		go func() { | 
 | 			defer wg.Done() | 
 | 			c, err := Dial(ln2.Addr().Network(), ln2.Addr().String()) | 
 | 			if err != nil { | 
 | 				if perr := parseDialError(err); perr != nil { | 
 | 					t.Error(perr) | 
 | 				} | 
 | 				t.Error(err) | 
 | 				return | 
 | 			} | 
 | 			c.Close() | 
 | 		}() | 
 | 		c, err := ln2.Accept() | 
 | 		if err != nil { | 
 | 			if perr := parseAcceptError(err); perr != nil { | 
 | 				t.Error(perr) | 
 | 			} | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		c.Close() | 
 | 		wg.Wait() | 
 | 		if !reflect.DeepEqual(ln2.Addr(), addr) { | 
 | 			t.Fatalf("got %#v; want %#v", ln2.Addr(), addr) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | var filePacketConnTests = []struct { | 
 | 	network string | 
 | }{ | 
 | 	{"udp"}, | 
 | 	{"unixgram"}, | 
 | } | 
 |  | 
 | func TestFilePacketConn(t *testing.T) { | 
 | 	switch runtime.GOOS { | 
 | 	case "plan9", "windows": | 
 | 		t.Skipf("not supported on %s", runtime.GOOS) | 
 | 	} | 
 |  | 
 | 	for _, tt := range filePacketConnTests { | 
 | 		if !testableNetwork(tt.network) { | 
 | 			t.Logf("skipping %s test", tt.network) | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		c1, err := newLocalPacketListener(tt.network) | 
 | 		if err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		switch tt.network { | 
 | 		case "unixgram": | 
 | 			defer os.Remove(c1.LocalAddr().String()) | 
 | 		} | 
 | 		addr := c1.LocalAddr() | 
 |  | 
 | 		var f *os.File | 
 | 		switch c1 := c1.(type) { | 
 | 		case *UDPConn: | 
 | 			f, err = c1.File() | 
 | 		case *UnixConn: | 
 | 			f, err = c1.File() | 
 | 		} | 
 | 		if err := c1.Close(); err != nil { | 
 | 			if perr := parseCloseError(err, false); perr != nil { | 
 | 				t.Error(perr) | 
 | 			} | 
 | 			t.Error(err) | 
 | 		} | 
 | 		if err != nil { | 
 | 			if perr := parseCommonError(err); perr != nil { | 
 | 				t.Error(perr) | 
 | 			} | 
 | 			t.Fatal(err) | 
 | 		} | 
 |  | 
 | 		c2, err := FilePacketConn(f) | 
 | 		if err := f.Close(); err != nil { | 
 | 			t.Error(err) | 
 | 		} | 
 | 		if err != nil { | 
 | 			if perr := parseCommonError(err); perr != nil { | 
 | 				t.Error(perr) | 
 | 			} | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		defer c2.Close() | 
 |  | 
 | 		if _, err := c2.WriteTo([]byte("FILEPACKETCONN TEST"), addr); err != nil { | 
 | 			if perr := parseWriteError(err); perr != nil { | 
 | 				t.Error(perr) | 
 | 			} | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		if !reflect.DeepEqual(c2.LocalAddr(), addr) { | 
 | 			t.Fatalf("got %#v; want %#v", c2.LocalAddr(), addr) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | // Issue 24483. | 
 | func TestFileCloseRace(t *testing.T) { | 
 | 	switch runtime.GOOS { | 
 | 	case "plan9", "windows": | 
 | 		t.Skipf("not supported on %s", runtime.GOOS) | 
 | 	} | 
 | 	if !testableNetwork("tcp") { | 
 | 		t.Skip("tcp not supported") | 
 | 	} | 
 |  | 
 | 	handler := func(ls *localServer, ln Listener) { | 
 | 		c, err := ln.Accept() | 
 | 		if err != nil { | 
 | 			return | 
 | 		} | 
 | 		defer c.Close() | 
 | 		var b [1]byte | 
 | 		c.Read(b[:]) | 
 | 	} | 
 |  | 
 | 	ls, err := newLocalServer("tcp") | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	defer ls.teardown() | 
 | 	if err := ls.buildup(handler); err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 |  | 
 | 	const tries = 100 | 
 | 	for i := 0; i < tries; i++ { | 
 | 		c1, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) | 
 | 		if err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 | 		tc := c1.(*TCPConn) | 
 |  | 
 | 		var wg sync.WaitGroup | 
 | 		wg.Add(2) | 
 | 		go func() { | 
 | 			defer wg.Done() | 
 | 			f, err := tc.File() | 
 | 			if err == nil { | 
 | 				f.Close() | 
 | 			} | 
 | 		}() | 
 | 		go func() { | 
 | 			defer wg.Done() | 
 | 			c1.Close() | 
 | 		}() | 
 | 		wg.Wait() | 
 | 	} | 
 | } |