145 lines
3.6 KiB
Go
145 lines
3.6 KiB
Go
|
// +build darwin dragonfly freebsd netbsd openbsd
|
||
|
|
||
|
package sockaddr
|
||
|
|
||
|
import (
|
||
|
"syscall"
|
||
|
"unsafe"
|
||
|
|
||
|
"golang.org/x/sys/unix"
|
||
|
)
|
||
|
|
||
|
func sockaddrToAny(sa unix.Sockaddr) (*unix.RawSockaddrAny, Socklen, error) {
|
||
|
if sa == nil {
|
||
|
return nil, 0, syscall.EINVAL
|
||
|
}
|
||
|
|
||
|
switch sa := sa.(type) {
|
||
|
case *unix.SockaddrInet4:
|
||
|
if sa.Port < 0 || sa.Port > 0xFFFF {
|
||
|
return nil, 0, syscall.EINVAL
|
||
|
}
|
||
|
var raw unix.RawSockaddrInet4
|
||
|
raw.Len = unix.SizeofSockaddrInet4
|
||
|
raw.Family = unix.AF_INET
|
||
|
p := (*[2]byte)(unsafe.Pointer(&raw.Port))
|
||
|
p[0] = byte(sa.Port >> 8)
|
||
|
p[1] = byte(sa.Port)
|
||
|
for i := 0; i < len(sa.Addr); i++ {
|
||
|
raw.Addr[i] = sa.Addr[i]
|
||
|
}
|
||
|
return (*unix.RawSockaddrAny)(unsafe.Pointer(&raw)), Socklen(raw.Len), nil
|
||
|
|
||
|
case *unix.SockaddrInet6:
|
||
|
if sa.Port < 0 || sa.Port > 0xFFFF {
|
||
|
return nil, 0, syscall.EINVAL
|
||
|
}
|
||
|
var raw unix.RawSockaddrInet6
|
||
|
raw.Len = unix.SizeofSockaddrInet6
|
||
|
raw.Family = unix.AF_INET6
|
||
|
p := (*[2]byte)(unsafe.Pointer(&raw.Port))
|
||
|
p[0] = byte(sa.Port >> 8)
|
||
|
p[1] = byte(sa.Port)
|
||
|
raw.Scope_id = sa.ZoneId
|
||
|
for i := 0; i < len(sa.Addr); i++ {
|
||
|
raw.Addr[i] = sa.Addr[i]
|
||
|
}
|
||
|
return (*unix.RawSockaddrAny)(unsafe.Pointer(&raw)), Socklen(raw.Len), nil
|
||
|
|
||
|
case *unix.SockaddrUnix:
|
||
|
name := sa.Name
|
||
|
n := len(name)
|
||
|
var raw unix.RawSockaddrUnix
|
||
|
if n >= len(raw.Path) || n == 0 {
|
||
|
return nil, 0, syscall.EINVAL
|
||
|
}
|
||
|
raw.Len = byte(3 + n) // 2 for Family, Len; 1 for NUL
|
||
|
raw.Family = unix.AF_UNIX
|
||
|
for i := 0; i < n; i++ {
|
||
|
raw.Path[i] = int8(name[i])
|
||
|
}
|
||
|
return (*unix.RawSockaddrAny)(unsafe.Pointer(&raw)), Socklen(raw.Len), nil
|
||
|
|
||
|
case *unix.SockaddrDatalink:
|
||
|
if sa.Index == 0 {
|
||
|
return nil, 0, syscall.EINVAL
|
||
|
}
|
||
|
var raw unix.RawSockaddrDatalink
|
||
|
raw.Len = sa.Len
|
||
|
raw.Family = unix.AF_LINK
|
||
|
raw.Index = sa.Index
|
||
|
raw.Type = sa.Type
|
||
|
raw.Nlen = sa.Nlen
|
||
|
raw.Alen = sa.Alen
|
||
|
raw.Slen = sa.Slen
|
||
|
for i := 0; i < len(raw.Data); i++ {
|
||
|
raw.Data[i] = sa.Data[i]
|
||
|
}
|
||
|
return (*unix.RawSockaddrAny)(unsafe.Pointer(&raw)), unix.SizeofSockaddrDatalink, nil
|
||
|
}
|
||
|
return nil, 0, syscall.EAFNOSUPPORT
|
||
|
}
|
||
|
|
||
|
func anyToSockaddr(rsa *unix.RawSockaddrAny) (unix.Sockaddr, error) {
|
||
|
if rsa == nil {
|
||
|
return nil, syscall.EINVAL
|
||
|
}
|
||
|
|
||
|
switch rsa.Addr.Family {
|
||
|
case unix.AF_LINK:
|
||
|
pp := (*unix.RawSockaddrDatalink)(unsafe.Pointer(rsa))
|
||
|
sa := new(unix.SockaddrDatalink)
|
||
|
sa.Len = pp.Len
|
||
|
sa.Family = pp.Family
|
||
|
sa.Index = pp.Index
|
||
|
sa.Type = pp.Type
|
||
|
sa.Nlen = pp.Nlen
|
||
|
sa.Alen = pp.Alen
|
||
|
sa.Slen = pp.Slen
|
||
|
for i := 0; i < len(sa.Data); i++ {
|
||
|
sa.Data[i] = pp.Data[i]
|
||
|
}
|
||
|
return sa, nil
|
||
|
|
||
|
case unix.AF_UNIX:
|
||
|
pp := (*unix.RawSockaddrUnix)(unsafe.Pointer(rsa))
|
||
|
if pp.Len < 3 || pp.Len > unix.SizeofSockaddrUnix {
|
||
|
return nil, syscall.EINVAL
|
||
|
}
|
||
|
sa := new(unix.SockaddrUnix)
|
||
|
n := int(pp.Len) - 3 // subtract leading Family, Len, terminating NUL
|
||
|
for i := 0; i < n; i++ {
|
||
|
if pp.Path[i] == 0 {
|
||
|
// found early NUL; assume Len is overestimating
|
||
|
n = i
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
|
||
|
sa.Name = string(bytes)
|
||
|
return sa, nil
|
||
|
|
||
|
case unix.AF_INET:
|
||
|
pp := (*unix.RawSockaddrInet4)(unsafe.Pointer(rsa))
|
||
|
sa := new(unix.SockaddrInet4)
|
||
|
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||
|
sa.Port = int(p[0])<<8 + int(p[1])
|
||
|
for i := 0; i < len(sa.Addr); i++ {
|
||
|
sa.Addr[i] = pp.Addr[i]
|
||
|
}
|
||
|
return sa, nil
|
||
|
|
||
|
case unix.AF_INET6:
|
||
|
pp := (*unix.RawSockaddrInet6)(unsafe.Pointer(rsa))
|
||
|
sa := new(unix.SockaddrInet6)
|
||
|
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||
|
sa.Port = int(p[0])<<8 + int(p[1])
|
||
|
sa.ZoneId = pp.Scope_id
|
||
|
for i := 0; i < len(sa.Addr); i++ {
|
||
|
sa.Addr[i] = pp.Addr[i]
|
||
|
}
|
||
|
return sa, nil
|
||
|
}
|
||
|
return nil, syscall.EAFNOSUPPORT
|
||
|
}
|