// Copyright 2009 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 aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows

package net

import (
	
	
)

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

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

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

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

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

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

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

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

func ( *sysDialer) ( context.Context, ,  *UDPAddr) (*UDPConn, error) {
	,  := internetSocket(, .network, , , syscall.SOCK_DGRAM, 0, "dial", .Dialer.Control)
	if  != nil {
		return nil, 
	}
	return newUDPConn(), nil
}

func ( *sysListener) ( context.Context,  *UDPAddr) (*UDPConn, error) {
	,  := internetSocket(, .network, , nil, syscall.SOCK_DGRAM, 0, "listen", .ListenConfig.Control)
	if  != nil {
		return nil, 
	}
	return newUDPConn(), nil
}

func ( *sysListener) ( context.Context,  *Interface,  *UDPAddr) (*UDPConn, error) {
	,  := internetSocket(, .network, , nil, syscall.SOCK_DGRAM, 0, "listen", .ListenConfig.Control)
	if  != nil {
		return nil, 
	}
	 := newUDPConn()
	if  := .IP.To4();  != nil {
		if  := listenIPv4MulticastUDP(, , );  != nil {
			.Close()
			return nil, 
		}
	} else {
		if  := listenIPv6MulticastUDP(, , .IP);  != nil {
			.Close()
			return nil, 
		}
	}
	return , nil
}

func listenIPv4MulticastUDP( *UDPConn,  *Interface,  IP) error {
	if  != nil {
		if  := setIPv4MulticastInterface(.fd, );  != nil {
			return 
		}
	}
	if  := setIPv4MulticastLoopback(.fd, false);  != nil {
		return 
	}
	if  := joinIPv4Group(.fd, , );  != nil {
		return 
	}
	return nil
}

func listenIPv6MulticastUDP( *UDPConn,  *Interface,  IP) error {
	if  != nil {
		if  := setIPv6MulticastInterface(.fd, );  != nil {
			return 
		}
	}
	if  := setIPv6MulticastLoopback(.fd, false);  != nil {
		return 
	}
	if  := joinIPv6Group(.fd, , );  != nil {
		return 
	}
	return nil
}