]> Cypherpunks repositories - gostls13.git/commitdiff
syscall: add socket control message support for darwin, freebsd, linux
authorMikio Hara <mikioh.mikioh@gmail.com>
Mon, 20 Jun 2011 22:40:20 +0000 (18:40 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 20 Jun 2011 22:40:20 +0000 (18:40 -0400)
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/4528113

14 files changed:
src/pkg/syscall/Makefile
src/pkg/syscall/route_bsd.go
src/pkg/syscall/sockcmsg_unix.go [new file with mode: 0644]
src/pkg/syscall/syscall_bsd.go
src/pkg/syscall/syscall_darwin_386.go
src/pkg/syscall/syscall_darwin_amd64.go
src/pkg/syscall/syscall_freebsd_386.go
src/pkg/syscall/syscall_freebsd_amd64.go
src/pkg/syscall/syscall_linux.go
src/pkg/syscall/syscall_unix.go
src/pkg/syscall/zsyscall_darwin_386.go
src/pkg/syscall/zsyscall_darwin_amd64.go
src/pkg/syscall/zsyscall_freebsd_386.go
src/pkg/syscall/zsyscall_freebsd_amd64.go

index c7f1b942c538cc36965f07d8b2eefca320e79fb2..d7bd58373b90f1d0892cfab21024f7c345715b7c 100644 (file)
@@ -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=\
index dded97b346e1414424f06f6a5a9232bb110325eb..7821a6d29b22dfdeb30b7bbc3e379ae5df8e365b 100644 (file)
@@ -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
diff --git a/src/pkg/syscall/sockcmsg_unix.go b/src/pkg/syscall/sockcmsg_unix.go
new file mode 100644 (file)
index 0000000..f0c05ea
--- /dev/null
@@ -0,0 +1,65 @@
+// 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
+}
index ec3b3167a8bd8afeeb380ded800d1b0acd206b27..2df75917b4b11aa939c4c55fe856246f96d17bfe 100644 (file)
@@ -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)
index 5101ba6c787859699c6dc97c754bfc77a0debda1..d76b22844bf777ea94ff8841a41c070de162dd67 100644 (file)
@@ -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
index acf7a55548191d210e284346621ad3f0182aac75..ed4372304955d0c62bf38cf194d4e1abf3e7b020 100644 (file)
@@ -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)
+}
index d0fa506c7e700169b41bc3b14bc0b57ff3459966..d3b5a1bfec39532bce730733865e19dad4f70bec 100644 (file)
@@ -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
index ef5aff6ef53e282d7afb74821915f091abe223af..8c1ddf6db4a2a830ecbd757f4ebc623d04047d75 100644 (file)
@@ -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)
+}
index 3b8f36da6388fe6556427d0e039ed4164a475d2a..1d6fc76c79d5618eb299c5550392b7c3d2591256 100644 (file)
@@ -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]))
index d17ef52d5c0718540b8636e46558a86150982ea7..20c8a135fe2521bdb778c3295ced2a20a25ef83e 100644 (file)
@@ -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)
index bbaceee19638ebb04a20fa835e8f6b625cde831c..436953ecaa613756f596e22e245959320cd7529b 100644 (file)
@@ -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)
index ee39eadc11a6e301f67dda332d9ea746e855e15d..1ba4c3cfe5541184f604fa2e5192f8f0ca298676 100644 (file)
@@ -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)
index 4f7fdefba18d4bec89dcde36b48dafa1eb11b0ae..d152e4380606c21bc67fa5b87c212a92ebb829b1 100644 (file)
@@ -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)
index 609ecdd2a9ee485a5aed78e0eb1b10e97eea8840..156b087e3987b81496fb6e8b17f8c424f9771029 100644 (file)
@@ -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)