// Copyright 2015 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.

package net

import (
	"internal/testenv"
	"os"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"testing"
)

var unixEnabledOnAIX bool

func init() {
	if runtime.GOOS == "aix" {
		// Unix network isn't properly working on AIX 7.2 with
		// Technical Level < 2.
		// The information is retrieved only once in this init()
		// instead of everytime testableNetwork is called.
		out, _ := exec.Command("oslevel", "-s").Output()
		if len(out) >= len("7200-XX-ZZ-YYMM") { // AIX 7.2, Tech Level XX, Service Pack ZZ, date YYMM
			aixVer := string(out[:4])
			tl, _ := strconv.Atoi(string(out[5:7]))
			unixEnabledOnAIX = aixVer > "7200" || (aixVer == "7200" && tl >= 2)
		}
	}
}

// testableNetwork reports whether network is testable on the current
// platform configuration.
func testableNetwork(network string) bool {
	ss := strings.Split(network, ":")
	switch ss[0] {
	case "ip+nopriv":
	case "ip", "ip4", "ip6":
		switch runtime.GOOS {
		case "plan9":
			return false
		default:
			if os.Getuid() != 0 {
				return false
			}
		}
	case "unix", "unixgram":
		switch runtime.GOOS {
		case "android", "plan9", "windows":
			return false
		case "aix":
			return unixEnabledOnAIX
		}
		// iOS does not support unix, unixgram.
		if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
			return false
		}
	case "unixpacket":
		switch runtime.GOOS {
		case "aix", "android", "darwin", "plan9", "windows":
			return false
		case "netbsd":
			// It passes on amd64 at least. 386 fails (Issue 22927). arm is unknown.
			if runtime.GOARCH == "386" {
				return false
			}
		}
	}
	switch ss[0] {
	case "tcp4", "udp4", "ip4":
		if !supportsIPv4() {
			return false
		}
	case "tcp6", "udp6", "ip6":
		if !supportsIPv6() {
			return false
		}
	}
	return true
}

// testableAddress reports whether address of network is testable on
// the current platform configuration.
func testableAddress(network, address string) bool {
	switch ss := strings.Split(network, ":"); ss[0] {
	case "unix", "unixgram", "unixpacket":
		// Abstract unix domain sockets, a Linux-ism.
		if address[0] == '@' && runtime.GOOS != "linux" {
			return false
		}
	}
	return true
}

// testableListenArgs reports whether arguments are testable on the
// current platform configuration.
func testableListenArgs(network, address, client string) bool {
	if !testableNetwork(network) || !testableAddress(network, address) {
		return false
	}

	var err error
	var addr Addr
	switch ss := strings.Split(network, ":"); ss[0] {
	case "tcp", "tcp4", "tcp6":
		addr, err = ResolveTCPAddr("tcp", address)
	case "udp", "udp4", "udp6":
		addr, err = ResolveUDPAddr("udp", address)
	case "ip", "ip4", "ip6":
		addr, err = ResolveIPAddr("ip", address)
	default:
		return true
	}
	if err != nil {
		return false
	}
	var ip IP
	var wildcard bool
	switch addr := addr.(type) {
	case *TCPAddr:
		ip = addr.IP
		wildcard = addr.isWildcard()
	case *UDPAddr:
		ip = addr.IP
		wildcard = addr.isWildcard()
	case *IPAddr:
		ip = addr.IP
		wildcard = addr.isWildcard()
	}

	// Test wildcard IP addresses.
	if wildcard && !testenv.HasExternalNetwork() {
		return false
	}

	// Test functionality of IPv4 communication using AF_INET and
	// IPv6 communication using AF_INET6 sockets.
	if !supportsIPv4() && ip.To4() != nil {
		return false
	}
	if !supportsIPv6() && ip.To16() != nil && ip.To4() == nil {
		return false
	}
	cip := ParseIP(client)
	if cip != nil {
		if !supportsIPv4() && cip.To4() != nil {
			return false
		}
		if !supportsIPv6() && cip.To16() != nil && cip.To4() == nil {
			return false
		}
	}

	// Test functionality of IPv4 communication using AF_INET6
	// sockets.
	if !supportsIPv4map() && supportsIPv4() && (network == "tcp" || network == "udp" || network == "ip") && wildcard {
		// At this point, we prefer IPv4 when ip is nil.
		// See favoriteAddrFamily for further information.
		if ip.To16() != nil && ip.To4() == nil && cip.To4() != nil { // a pair of IPv6 server and IPv4 client
			return false
		}
		if (ip.To4() != nil || ip == nil) && cip.To16() != nil && cip.To4() == nil { // a pair of IPv4 server and IPv6 client
			return false
		}
	}

	return true
}

func condFatalf(t *testing.T, network string, format string, args ...interface{}) {
	t.Helper()
	// A few APIs like File and Read/WriteMsg{UDP,IP} are not
	// fully implemented yet on Plan 9 and Windows.
	switch runtime.GOOS {
	case "windows":
		if network == "file+net" {
			t.Logf(format, args...)
			return
		}
	case "plan9":
		t.Logf(format, args...)
		return
	}
	t.Fatalf(format, args...)
}
