// 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 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package socket import ( "net" "unsafe" "golang.org/x/sys/unix" ) //go:linkname syscall_getsockopt syscall.getsockopt func syscall_getsockopt(s, level, name int, val unsafe.Pointer, vallen *uint32) error //go:linkname syscall_setsockopt syscall.setsockopt func syscall_setsockopt(s, level, name int, val unsafe.Pointer, vallen uintptr) error func getsockopt(s uintptr, level, name int, b []byte) (int, error) { l := uint32(len(b)) err := syscall_getsockopt(int(s), level, name, unsafe.Pointer(&b[0]), &l) return int(l), err } func setsockopt(s uintptr, level, name int, b []byte) error { return syscall_setsockopt(int(s), level, name, unsafe.Pointer(&b[0]), uintptr(len(b))) } func recvmsg(s uintptr, buffers [][]byte, oob []byte, flags int, network string) (n, oobn int, recvflags int, from net.Addr, err error) { var unixFrom unix.Sockaddr n, oobn, recvflags, unixFrom, err = unix.RecvmsgBuffers(int(s), buffers, oob, flags) if unixFrom != nil { from = sockaddrToAddr(unixFrom, network) } return } func sendmsg(s uintptr, buffers [][]byte, oob []byte, to net.Addr, flags int) (int, error) { var unixTo unix.Sockaddr if to != nil { unixTo = addrToSockaddr(to) } return unix.SendmsgBuffers(int(s), buffers, oob, unixTo, flags) } // addrToSockaddr converts a net.Addr to a unix.Sockaddr. func addrToSockaddr(a net.Addr) unix.Sockaddr { var ( ip net.IP port int zone string ) switch a := a.(type) { case *net.TCPAddr: ip = a.IP port = a.Port zone = a.Zone case *net.UDPAddr: ip = a.IP port = a.Port zone = a.Zone case *net.IPAddr: ip = a.IP zone = a.Zone default: return nil } if ip4 := ip.To4(); ip4 != nil { sa := unix.SockaddrInet4{Port: port} copy(sa.Addr[:], ip4) return &sa } if ip6 := ip.To16(); ip6 != nil && ip.To4() == nil { sa := unix.SockaddrInet6{Port: port} copy(sa.Addr[:], ip6) if zone != "" { sa.ZoneId = uint32(zoneCache.index(zone)) } return &sa } return nil } // sockaddrToAddr converts a unix.Sockaddr to a net.Addr. func sockaddrToAddr(sa unix.Sockaddr, network string) net.Addr { var ( ip net.IP port int zone string ) switch sa := sa.(type) { case *unix.SockaddrInet4: ip = make(net.IP, net.IPv4len) copy(ip, sa.Addr[:]) port = sa.Port case *unix.SockaddrInet6: ip = make(net.IP, net.IPv6len) copy(ip, sa.Addr[:]) port = sa.Port if sa.ZoneId > 0 { zone = zoneCache.name(int(sa.ZoneId)) } default: return nil } switch network { case "tcp", "tcp4", "tcp6": return &net.TCPAddr{IP: ip, Port: port, Zone: zone} case "udp", "udp4", "udp6": return &net.UDPAddr{IP: ip, Port: port, Zone: zone} default: return &net.IPAddr{IP: ip, Zone: zone} } }