// Copyright 2010 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 unix || js || wasip1 || windows

package net

import (
	
	
)

func sockaddrToIP( syscall.Sockaddr) Addr {
	switch sa := .(type) {
	case *syscall.SockaddrInet4:
		return &IPAddr{IP: .Addr[0:]}
	case *syscall.SockaddrInet6:
		return &IPAddr{IP: .Addr[0:], Zone: zoneCache.name(int(.ZoneId))}
	}
	return nil
}

func ( *IPAddr) () int {
	if  == nil || len(.IP) <= IPv4len {
		return syscall.AF_INET
	}
	if .IP.To4() != nil {
		return syscall.AF_INET
	}
	return syscall.AF_INET6
}

func ( *IPAddr) ( int) (syscall.Sockaddr, error) {
	if  == nil {
		return nil, nil
	}
	return ipToSockaddr(, .IP, 0, .Zone)
}

func ( *IPAddr) ( string) sockaddr {
	return &IPAddr{loopbackIP(), .Zone}
}

func ( *IPConn) ( []byte) (int, *IPAddr, error) {
	// TODO(cw,rsc): consider using readv if we know the family
	// type to avoid the header trim/copy
	var  *IPAddr
	, ,  := .fd.readFrom()
	switch sa := .(type) {
	case *syscall.SockaddrInet4:
		 = &IPAddr{IP: .Addr[0:]}
		 = stripIPv4Header(, )
	case *syscall.SockaddrInet6:
		 = &IPAddr{IP: .Addr[0:], Zone: zoneCache.name(int(.ZoneId))}
	}
	return , , 
}

func stripIPv4Header( int,  []byte) int {
	if len() < 20 {
		return 
	}
	 := int([0]&0x0f) << 2
	if 20 >  ||  > len() {
		return 
	}
	if [0]>>4 != 4 {
		return 
	}
	copy(, [:])
	return  - 
}

func ( *IPConn) (,  []byte) (, ,  int,  *IPAddr,  error) {
	var  syscall.Sockaddr
	, , , ,  = .fd.readMsg(, , 0)
	switch sa := .(type) {
	case *syscall.SockaddrInet4:
		 = &IPAddr{IP: .Addr[0:]}
	case *syscall.SockaddrInet6:
		 = &IPAddr{IP: .Addr[0:], Zone: zoneCache.name(int(.ZoneId))}
	}
	return
}

func ( *IPConn) ( []byte,  *IPAddr) (int, error) {
	if .fd.isConnected {
		return 0, ErrWriteToConnected
	}
	if  == nil {
		return 0, errMissingAddress
	}
	,  := .sockaddr(.fd.family)
	if  != nil {
		return 0, 
	}
	return .fd.writeTo(, )
}

func ( *IPConn) (,  []byte,  *IPAddr) (,  int,  error) {
	if .fd.isConnected {
		return 0, 0, ErrWriteToConnected
	}
	if  == nil {
		return 0, 0, errMissingAddress
	}
	,  := .sockaddr(.fd.family)
	if  != nil {
		return 0, 0, 
	}
	return .fd.writeMsg(, , )
}

func ( *sysDialer) ( context.Context, ,  *IPAddr) (*IPConn, error) {
	, ,  := parseNetwork(, .network, true)
	if  != nil {
		return nil, 
	}
	switch  {
	case "ip", "ip4", "ip6":
	default:
		return nil, UnknownNetworkError(.network)
	}
	 := .Dialer.ControlContext
	if  == nil && .Dialer.Control != nil {
		 = func( context.Context, ,  string,  syscall.RawConn) error {
			return .Dialer.Control(, , )
		}
	}
	,  := internetSocket(, , , , syscall.SOCK_RAW, , "dial", )
	if  != nil {
		return nil, 
	}
	return newIPConn(), nil
}

func ( *sysListener) ( context.Context,  *IPAddr) (*IPConn, error) {
	, ,  := parseNetwork(, .network, true)
	if  != nil {
		return nil, 
	}
	switch  {
	case "ip", "ip4", "ip6":
	default:
		return nil, UnknownNetworkError(.network)
	}
	var  func( context.Context, ,  string,  syscall.RawConn) error
	if .ListenConfig.Control != nil {
		 = func( context.Context, ,  string,  syscall.RawConn) error {
			return .ListenConfig.Control(, , )
		}
	}
	,  := internetSocket(, , , nil, syscall.SOCK_RAW, , "listen", )
	if  != nil {
		return nil, 
	}
	return newIPConn(), nil
}