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

//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows || zos

package socket

import (
	
	
	
	
	
	
	
)

// marshalInetAddr writes a in sockaddr format into the buffer b.
// The buffer must be sufficiently large (sizeofSockaddrInet4/6).
// Returns the number of bytes written.
func marshalInetAddr( net.Addr,  []byte) int {
	switch a := .(type) {
	case *net.TCPAddr:
		return marshalSockaddr(.IP, .Port, .Zone, )
	case *net.UDPAddr:
		return marshalSockaddr(.IP, .Port, .Zone, )
	case *net.IPAddr:
		return marshalSockaddr(.IP, 0, .Zone, )
	default:
		return 0
	}
}

func marshalSockaddr( net.IP,  int,  string,  []byte) int {
	if  := .To4();  != nil {
		switch runtime.GOOS {
		case "android", "illumos", "linux", "solaris", "windows":
			NativeEndian.PutUint16([:2], uint16(sysAF_INET))
		default:
			[0] = sizeofSockaddrInet4
			[1] = sysAF_INET
		}
		binary.BigEndian.PutUint16([2:4], uint16())
		copy([4:8], )
		return sizeofSockaddrInet4
	}
	if  := .To16();  != nil && .To4() == nil {
		switch runtime.GOOS {
		case "android", "illumos", "linux", "solaris", "windows":
			NativeEndian.PutUint16([:2], uint16(sysAF_INET6))
		default:
			[0] = sizeofSockaddrInet6
			[1] = sysAF_INET6
		}
		binary.BigEndian.PutUint16([2:4], uint16())
		copy([8:24], )
		if  != "" {
			NativeEndian.PutUint32([24:28], uint32(zoneCache.index()))
		}
		return sizeofSockaddrInet6
	}
	return 0
}

func parseInetAddr( []byte,  string) (net.Addr, error) {
	if len() < 2 {
		return nil, errors.New("invalid address")
	}
	var  int
	switch runtime.GOOS {
	case "android", "illumos", "linux", "solaris", "windows":
		 = int(NativeEndian.Uint16([:2]))
	default:
		 = int([1])
	}
	var  net.IP
	var  string
	if  == sysAF_INET {
		if len() < sizeofSockaddrInet4 {
			return nil, errors.New("short address")
		}
		 = make(net.IP, net.IPv4len)
		copy(, [4:8])
	}
	if  == sysAF_INET6 {
		if len() < sizeofSockaddrInet6 {
			return nil, errors.New("short address")
		}
		 = make(net.IP, net.IPv6len)
		copy(, [8:24])
		if  := int(NativeEndian.Uint32([24:28]));  > 0 {
			 = zoneCache.name()
		}
	}
	switch  {
	case "tcp", "tcp4", "tcp6":
		return &net.TCPAddr{IP: , Port: int(binary.BigEndian.Uint16([2:4])), Zone: }, nil
	case "udp", "udp4", "udp6":
		return &net.UDPAddr{IP: , Port: int(binary.BigEndian.Uint16([2:4])), Zone: }, nil
	default:
		return &net.IPAddr{IP: , Zone: }, nil
	}
}

// An ipv6ZoneCache represents a cache holding partial network
// interface information. It is used for reducing the cost of IPv6
// addressing scope zone resolution.
//
// Multiple names sharing the index are managed by first-come
// first-served basis for consistency.
type ipv6ZoneCache struct {
	sync.RWMutex                // guard the following
	lastFetched  time.Time      // last time routing information was fetched
	toIndex      map[string]int // interface name to its index
	toName       map[int]string // interface index to its name
}

var zoneCache = ipv6ZoneCache{
	toIndex: make(map[string]int),
	toName:  make(map[int]string),
}

// update refreshes the network interface information if the cache was last
// updated more than 1 minute ago, or if force is set. It returns whether the
// cache was updated.
func ( *ipv6ZoneCache) ( []net.Interface,  bool) ( bool) {
	.Lock()
	defer .Unlock()
	 := time.Now()
	if ! && .lastFetched.After(.Add(-60*time.Second)) {
		return false
	}
	.lastFetched = 
	if len() == 0 {
		var  error
		if ,  = net.Interfaces();  != nil {
			return false
		}
	}
	.toIndex = make(map[string]int, len())
	.toName = make(map[int]string, len())
	for ,  := range  {
		.toIndex[.Name] = .Index
		if ,  := .toName[.Index]; ! {
			.toName[.Index] = .Name
		}
	}
	return true
}

func ( *ipv6ZoneCache) ( int) string {
	 := zoneCache.update(nil, false)
	zoneCache.RLock()
	,  := zoneCache.toName[]
	zoneCache.RUnlock()
	if ! && ! {
		zoneCache.update(nil, true)
		zoneCache.RLock()
		,  = zoneCache.toName[]
		zoneCache.RUnlock()
	}
	if ! { // last resort
		 = strconv.Itoa()
	}
	return 
}

func ( *ipv6ZoneCache) ( string) int {
	 := zoneCache.update(nil, false)
	zoneCache.RLock()
	,  := zoneCache.toIndex[]
	zoneCache.RUnlock()
	if ! && ! {
		zoneCache.update(nil, true)
		zoneCache.RLock()
		,  = zoneCache.toIndex[]
		zoneCache.RUnlock()
	}
	if ! { // last resort
		, _ = strconv.Atoi()
	}
	return 
}