Commit 5d6f118f authored by Mikio Hara's avatar Mikio Hara Committed by Russ Cox

syscall: add socket control message support for darwin, freebsd, linux

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/4528113
parent 97a929aa
......@@ -20,6 +20,7 @@ GOFILES_freebsd=\
bpf_bsd.go\
exec_unix.go\
route_bsd.go\
sockcmsg_unix.go\
syscall_bsd.go\
syscall_unix.go\
......@@ -27,6 +28,7 @@ GOFILES_darwin=\
bpf_bsd.go\
exec_unix.go\
route_bsd.go\
sockcmsg_unix.go\
syscall_bsd.go\
syscall_unix.go\
......@@ -34,6 +36,7 @@ GOFILES_linux=\
exec_unix.go\
lsf_linux.go\
netlink_linux.go\
sockcmsg_unix.go\
syscall_unix.go\
GOFILES_windows=\
......
......@@ -10,8 +10,6 @@ import (
"unsafe"
)
const darwinAMD64 = OS == "darwin" && ARCH == "amd64"
// Round the length of a raw sockaddr up to align it properly.
func rsaAlignOf(salen int) int {
salign := sizeofPtr
......
// Copyright 2011 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.
// Socket control messages
package syscall
import (
"unsafe"
)
// Round the length of a raw sockaddr up to align it propery.
func cmsgAlignOf(salen int) int {
salign := sizeofPtr
// NOTE: It seems like 64-bit Darwin kernel still requires 32-bit
// aligned access to BSD subsystem.
if darwinAMD64 {
salign = 4
}
if salen == 0 {
return salign
}
return (salen + salign - 1) & ^(salign - 1)
}
func cmsgLen(datalen int) int {
return cmsgAlignOf(SizeofCmsghdr) + datalen
}
type SocketControlMessage struct {
Header Cmsghdr
Data []byte
}
func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, int) {
var (
h *Cmsghdr
dbuf []byte
e int
cmsgs []SocketControlMessage
)
for len(buf) >= cmsgLen(0) {
h, dbuf, e = socketControlMessageHeaderAndData(buf)
if e != 0 {
break
}
m := SocketControlMessage{}
m.Header = *h
m.Data = dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]
cmsgs = append(cmsgs, m)
buf = buf[cmsgAlignOf(int(h.Len)):]
}
return cmsgs, e
}
func socketControlMessageHeaderAndData(buf []byte) (*Cmsghdr, []byte, int) {
h := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
if h.Len < SizeofCmsghdr || int(h.Len) > len(buf) {
return nil, nil, EINVAL
}
return h, buf[cmsgAlignOf(SizeofCmsghdr):], 0
}
......@@ -425,6 +425,80 @@ func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int) {
return sendto(fd, p, flags, ptr, n)
}
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, errno int)
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, errno int) {
var msg Msghdr
var rsa RawSockaddrAny
msg.Name = (*byte)(unsafe.Pointer(&rsa))
msg.Namelen = uint32(SizeofSockaddrAny)
var iov Iovec
if len(p) > 0 {
iov.Base = (*byte)(unsafe.Pointer(&p[0]))
iov.SetLen(len(p))
}
var dummy byte
if len(oob) > 0 {
// receive at least one normal byte
if len(p) == 0 {
iov.Base = &dummy
iov.SetLen(1)
}
msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
msg.SetControllen(len(oob))
}
msg.Iov = &iov
msg.Iovlen = 1
if n, errno = recvmsg(fd, &msg, flags); errno != 0 {
return
}
oobn = int(msg.Controllen)
recvflags = int(msg.Flags)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
from, errno = anyToSockaddr(&rsa)
}
return
}
//sys sendmsg(s int, msg *Msghdr, flags int) (errno int)
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
var ptr uintptr
var salen _Socklen
if to != nil {
var err int
ptr, salen, err = to.sockaddr()
if err != 0 {
return err
}
}
var msg Msghdr
msg.Name = (*byte)(unsafe.Pointer(ptr))
msg.Namelen = uint32(salen)
var iov Iovec
if len(p) > 0 {
iov.Base = (*byte)(unsafe.Pointer(&p[0]))
iov.SetLen(len(p))
}
var dummy byte
if len(oob) > 0 {
// send at least one normal byte
if len(p) == 0 {
iov.Base = &dummy
iov.SetLen(1)
}
msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
msg.SetControllen(len(oob))
}
msg.Iov = &iov
msg.Iovlen = 1
if errno = sendmsg(fd, &msg, flags); errno != 0 {
return
}
return
}
// TODO:
// FreeBSD has IP_SENDIF. Darwin probably needs BSDLLCTest, see:
// http://developer.apple.com/mac/library/samplecode/BSDLLCTest/index.html
......@@ -540,14 +614,6 @@ func Futimes(fd int, tv []Timeval) (errno int) {
//sys fcntl(fd int, cmd int, arg int) (val int, errno int)
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, errno int) {
return 0, 0, 0, nil, EAFNOSUPPORT
}
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
return EAFNOSUPPORT
}
// TODO: wrap
// Acct(name nil-string) (errno int)
// Gethostuuid(uuid *byte, timeout *Timespec) (errno int)
......
......@@ -40,4 +40,16 @@ func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Flags = uint16(flags)
}
func (iov *Iovec) SetLen(length int) {
iov.Len = uint32(length)
}
func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) // sic
......@@ -39,3 +39,15 @@ func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Filter = int16(mode)
k.Flags = uint16(flags)
}
func (iov *Iovec) SetLen(length int) {
iov.Len = uint64(length)
}
func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
......@@ -29,4 +29,16 @@ func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Flags = uint16(flags)
}
func (iov *Iovec) SetLen(length int) {
iov.Len = uint32(length)
}
func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) // sic
......@@ -28,3 +28,15 @@ func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Filter = int16(mode)
k.Flags = uint16(flags)
}
func (iov *Iovec) SetLen(length int) {
iov.Len = uint64(length)
}
func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
......@@ -529,17 +529,17 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
var ptr uintptr
var nsock _Socklen
var salen _Socklen
if to != nil {
var err int
ptr, nsock, err = to.sockaddr()
ptr, salen, err = to.sockaddr()
if err != 0 {
return err
}
}
var msg Msghdr
msg.Name = (*byte)(unsafe.Pointer(ptr))
msg.Namelen = uint32(nsock)
msg.Namelen = uint32(salen)
var iov Iovec
if len(p) > 0 {
iov.Base = (*byte)(unsafe.Pointer(&p[0]))
......
......@@ -16,6 +16,8 @@ var (
Stderr = 2
)
const darwinAMD64 = OS == "darwin" && ARCH == "amd64"
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
......
......@@ -154,6 +154,23 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
n = int(r0)
errno = int(e1)
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
errno = int(e1)
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
......
......@@ -154,6 +154,23 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
n = int(r0)
errno = int(e1)
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
errno = int(e1)
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
......
......@@ -154,6 +154,23 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
n = int(r0)
errno = int(e1)
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
errno = int(e1)
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
......
......@@ -154,6 +154,23 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
n = int(r0)
errno = int(e1)
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
errno = int(e1)
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment