aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbert Strasheim <fullung@gmail.com>2010-12-07 13:40:14 -0500
committerRuss Cox <rsc@golang.org>2010-12-07 13:40:14 -0500
commitcf6c2121979dacdb712c5ec9124043a8e6acf89e (patch)
treeea43fb3cbc66564fcf4ef7405f5056767aa9cf34
parented7c3f312711f0883532a806ce1ead0b2724a73b (diff)
downloadgo-cf6c2121979dacdb712c5ec9124043a8e6acf89e.tar.gz
go-cf6c2121979dacdb712c5ec9124043a8e6acf89e.zip
syscall, net: Add Recvmsg and Sendmsg on Linux.
Working on issue 1101. R=rsc CC=golang-dev https://golang.org/cl/2331044
-rw-r--r--src/pkg/net/fd.go71
-rw-r--r--src/pkg/net/fd_windows.go8
-rw-r--r--src/pkg/net/unixsock.go26
-rwxr-xr-xsrc/pkg/syscall/mkerrors.sh6
-rw-r--r--src/pkg/syscall/syscall_bsd.go9
-rw-r--r--src/pkg/syscall/syscall_linux.go68
-rw-r--r--src/pkg/syscall/syscall_linux_386.go22
-rw-r--r--src/pkg/syscall/syscall_linux_amd64.go14
-rw-r--r--src/pkg/syscall/zerrors_linux_386.go45
-rw-r--r--src/pkg/syscall/zerrors_linux_amd64.go45
-rw-r--r--src/pkg/syscall/zsyscall_linux_amd64.go17
11 files changed, 326 insertions, 5 deletions
diff --git a/src/pkg/net/fd.go b/src/pkg/net/fd.go
index d300e4bda5..b2e24f5986 100644
--- a/src/pkg/net/fd.go
+++ b/src/pkg/net/fd.go
@@ -401,6 +401,42 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
return
}
+func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err os.Error) {
+ if fd == nil || fd.sysfile == nil {
+ return 0, 0, 0, nil, os.EINVAL
+ }
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.rdeadline_delta > 0 {
+ fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
+ } else {
+ fd.rdeadline = 0
+ }
+ var oserr os.Error
+ for {
+ var errno int
+ n, oobn, flags, errno = syscall.Recvmsg(fd.sysfd, p, oob, sa, 0)
+ if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
+ pollserver.WaitRead(fd)
+ continue
+ }
+ if errno != 0 {
+ oserr = os.Errno(errno)
+ }
+ if n == 0 {
+ oserr = os.EOF
+ }
+ break
+ }
+ if oserr != nil {
+ err = &OpError{"read", fd.net, fd.laddr, oserr}
+ return
+ }
+ return
+}
+
func (fd *netFD) Write(p []byte) (n int, err os.Error) {
if fd == nil {
return 0, os.EINVAL
@@ -481,6 +517,41 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
return
}
+func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err os.Error) {
+ if fd == nil || fd.sysfile == nil {
+ return 0, 0, os.EINVAL
+ }
+ fd.wio.Lock()
+ defer fd.wio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.wdeadline_delta > 0 {
+ fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
+ } else {
+ fd.wdeadline = 0
+ }
+ var oserr os.Error
+ for {
+ var errno int
+ errno = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
+ if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
+ pollserver.WaitWrite(fd)
+ continue
+ }
+ if errno != 0 {
+ oserr = os.Errno(errno)
+ }
+ break
+ }
+ if oserr == nil {
+ n = len(p)
+ oobn = len(oob)
+ } else {
+ err = &OpError{"write", fd.net, fd.raddr, oserr}
+ }
+ return
+}
+
func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
if fd == nil || fd.sysfile == nil {
return nil, os.EINVAL
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 75e2e4f2d1..64eed4ab97 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -445,3 +445,11 @@ func (fd *netFD) dup() (f *os.File, err os.Error) {
// TODO: Implement this
return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
}
+
+func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err os.Error) {
+ return 0, 0, 0, nil, os.EAFNOSUPPORT
+}
+
+func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err os.Error) {
+ return 0, 0, os.EAFNOSUPPORT
+}
diff --git a/src/pkg/net/unixsock.go b/src/pkg/net/unixsock.go
index 82c0b6d05b..1c15e5e97f 100644
--- a/src/pkg/net/unixsock.go
+++ b/src/pkg/net/unixsock.go
@@ -277,6 +277,32 @@ func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
return c.WriteToUnix(b, a)
}
+func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err os.Error) {
+ if !c.ok() {
+ return 0, 0, 0, nil, os.EINVAL
+ }
+ n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrUnix:
+ addr = &UnixAddr{sa.Name, c.fd.proto == syscall.SOCK_DGRAM}
+ }
+ return
+}
+
+func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err os.Error) {
+ if !c.ok() {
+ return 0, 0, os.EINVAL
+ }
+ if addr != nil {
+ if addr.Datagram != (c.fd.proto == syscall.SOCK_DGRAM) {
+ return 0, 0, os.EAFNOSUPPORT
+ }
+ sa := &syscall.SockaddrUnix{Name: addr.Name}
+ return c.fd.WriteMsg(b, oob, sa)
+ }
+ return c.fd.WriteMsg(b, oob, nil)
+}
+
// File returns a copy of the underlying os.File, set to blocking mode.
// It is the caller's responsibility to close f when finished.
// Closing c does not affect f, and closing f does not affect c.
diff --git a/src/pkg/syscall/mkerrors.sh b/src/pkg/syscall/mkerrors.sh
index f7b4adb14f..f3fb942700 100755
--- a/src/pkg/syscall/mkerrors.sh
+++ b/src/pkg/syscall/mkerrors.sh
@@ -25,6 +25,8 @@ includes_Linux='
#include <sys/epoll.h>
#include <sys/inotify.h>
#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
#include <linux/ptrace.h>
#include <linux/wait.h>
#include <netpacket/packet.h>
@@ -84,11 +86,13 @@ done
$2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next} # 386 registers
$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next}
+ $2 ~ /^(SCM_SRCRT)$/ {next}
+ $2 ~ /^(MAP_FAILED)$/ {next}
$2 ~ /^E[A-Z0-9_]+$/ ||
$2 ~ /^SIG[^_]/ ||
$2 ~ /^IN_/ ||
- $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|EVFILT|EV|SHUT|PROT|MAP|PACKET)_/ ||
+ $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|EVFILT|EV|SHUT|PROT|MAP|PACKET|MSG|SCM)_/ ||
$2 == "SOMAXCONN" ||
$2 == "NAME_MAX" ||
$2 ~ /^(O|F|FD|NAME|S|PTRACE)_/ ||
diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go
index 767537093e..ff99fd9e6d 100644
--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -485,6 +485,13 @@ 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, from Sockaddr, flags int) (n, oobn int, recvflags int, errno int) {
+ return 0, 0, 0, EAFNOSUPPORT
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
+ return EAFNOSUPPORT
+}
// TODO: wrap
// Acct(name nil-string) (errno int)
@@ -495,5 +502,3 @@ func Futimes(fd int, tv []Timeval) (errno int) {
// Msync(addr *byte, len int, flags int) (errno int)
// Munmap(addr *byte, len int) (errno int)
// Ptrace(req int, pid int, addr uintptr, data int) (ret uintptr, errno int)
-// Recvmsg(s int, msg *Msghdr, flags int) (n int, errno int)
-// Sendmsg(s int, msg *Msghdr, flags int) (n int, errno int)
diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go
index d34956c31d..710ab74fa5 100644
--- a/src/pkg/syscall/syscall_linux.go
+++ b/src/pkg/syscall/syscall_linux.go
@@ -447,6 +447,72 @@ func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int) {
return sendto(fd, p, flags, ptr, n)
}
+func Recvmsg(fd int, p, oob []byte, from Sockaddr, flags int) (n, oobn int, recvflags int, 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)
+ return
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
+ var ptr uintptr
+ var nsock _Socklen
+ if to != nil {
+ var err int
+ ptr, nsock, err = to.sockaddr()
+ if err != 0 {
+ return err
+ }
+ }
+ var msg Msghdr
+ msg.Name = (*byte)(unsafe.Pointer(ptr))
+ msg.Namelen = uint32(nsock)
+ 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
+}
+
// BindToDevice binds the socket associated with fd to device.
func BindToDevice(fd int, device string) (errno int) {
return SetsockoptString(fd, SOL_SOCKET, SO_BINDTODEVICE, device)
@@ -592,8 +658,6 @@ func PtraceDetach(pid int) (errno int) { return ptrace(PTRACE_DETACH, pid, 0, 0)
// Sendto
// Recvfrom
-// Sendmsg
-// Recvmsg
// Socketpair
// Getsockopt
diff --git a/src/pkg/syscall/syscall_linux_386.go b/src/pkg/syscall/syscall_linux_386.go
index 88b3034346..bf5dd47d1e 100644
--- a/src/pkg/syscall/syscall_linux_386.go
+++ b/src/pkg/syscall/syscall_linux_386.go
@@ -151,6 +151,16 @@ func sendto(s int, p []byte, flags int, to uintptr, addrlen _Socklen) (errno int
return
}
+func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
+ n, errno = socketcall(_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+ return
+}
+
+func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
+ _, errno = socketcall(_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+ return
+}
+
func Listen(s int, n int) (errno int) {
_, errno = socketcall(_LISTEN, uintptr(s), uintptr(n), 0, 0, 0, 0)
return
@@ -176,3 +186,15 @@ func Statfs(path string, buf *Statfs_t) (errno int) {
func (r *PtraceRegs) PC() uint64 { return uint64(uint32(r.Eip)) }
func (r *PtraceRegs) SetPC(pc uint64) { r.Eip = int32(pc) }
+
+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)
+}
diff --git a/src/pkg/syscall/syscall_linux_amd64.go b/src/pkg/syscall/syscall_linux_amd64.go
index fda8260689..0b8ccb0d5d 100644
--- a/src/pkg/syscall/syscall_linux_amd64.go
+++ b/src/pkg/syscall/syscall_linux_amd64.go
@@ -46,6 +46,8 @@ package syscall
//sys getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int)
//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno int)
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, errno int)
+//sys sendmsg(s int, msg *Msghdr, flags int) (errno int)
func Getpagesize() int { return 4096 }
@@ -72,3 +74,15 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
func (r *PtraceRegs) PC() uint64 { return r.Rip }
func (r *PtraceRegs) SetPC(pc uint64) { r.Rip = pc }
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint64(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint64(length)
+}
diff --git a/src/pkg/syscall/zerrors_linux_386.go b/src/pkg/syscall/zerrors_linux_386.go
index c6b31a19bd..f685367603 100644
--- a/src/pkg/syscall/zerrors_linux_386.go
+++ b/src/pkg/syscall/zerrors_linux_386.go
@@ -385,6 +385,40 @@ const (
IP_TOS = 0x1
IP_TTL = 0x2
IP_UNBLOCK_SOURCE = 0x25
+ MAP_32BIT = 0x40
+ MAP_ANON = 0x20
+ MAP_ANONYMOUS = 0x20
+ MAP_DENYWRITE = 0x800
+ MAP_EXECUTABLE = 0x1000
+ MAP_FILE = 0
+ MAP_FIXED = 0x10
+ MAP_GROWSDOWN = 0x100
+ MAP_LOCKED = 0x2000
+ MAP_NONBLOCK = 0x10000
+ MAP_NORESERVE = 0x4000
+ MAP_POPULATE = 0x8000
+ MAP_PRIVATE = 0x2
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x20000
+ MAP_TYPE = 0xf
+ MSG_CMSG_CLOEXEC = 0x40000000
+ MSG_CONFIRM = 0x800
+ MSG_CTRUNC = 0x8
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x40
+ MSG_EOR = 0x80
+ MSG_ERRQUEUE = 0x2000
+ MSG_FIN = 0x200
+ MSG_MORE = 0x8000
+ MSG_NOSIGNAL = 0x4000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_PROXY = 0x10
+ MSG_RST = 0x1000
+ MSG_SYN = 0x400
+ MSG_TRUNC = 0x20
+ MSG_TRYHARD = 0x4
+ MSG_WAITALL = 0x100
NAME_MAX = 0xff
O_ACCMODE = 0x3
O_APPEND = 0x400
@@ -423,6 +457,12 @@ const (
PACKET_RECV_OUTPUT = 0x3
PACKET_RX_RING = 0x5
PACKET_STATISTICS = 0x6
+ PROT_EXEC = 0x4
+ PROT_GROWSDOWN = 0x1000000
+ PROT_GROWSUP = 0x2000000
+ PROT_NONE = 0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
PTRACE_ATTACH = 0x10
PTRACE_BTS_CLEAR = 0x2c
PTRACE_BTS_CONFIG = 0x28
@@ -476,6 +516,11 @@ const (
PTRACE_SYSEMU = 0x1f
PTRACE_SYSEMU_SINGLESTEP = 0x20
PTRACE_TRACEME = 0
+ SCM_CREDENTIALS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x1d
+ SCM_TIMESTAMPING = 0x25
+ SCM_TIMESTAMPNS = 0x23
SHUT_RD = 0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
diff --git a/src/pkg/syscall/zerrors_linux_amd64.go b/src/pkg/syscall/zerrors_linux_amd64.go
index 9a5f035fd6..bfe86bbe44 100644
--- a/src/pkg/syscall/zerrors_linux_amd64.go
+++ b/src/pkg/syscall/zerrors_linux_amd64.go
@@ -385,6 +385,40 @@ const (
IP_TOS = 0x1
IP_TTL = 0x2
IP_UNBLOCK_SOURCE = 0x25
+ MAP_32BIT = 0x40
+ MAP_ANON = 0x20
+ MAP_ANONYMOUS = 0x20
+ MAP_DENYWRITE = 0x800
+ MAP_EXECUTABLE = 0x1000
+ MAP_FILE = 0
+ MAP_FIXED = 0x10
+ MAP_GROWSDOWN = 0x100
+ MAP_LOCKED = 0x2000
+ MAP_NONBLOCK = 0x10000
+ MAP_NORESERVE = 0x4000
+ MAP_POPULATE = 0x8000
+ MAP_PRIVATE = 0x2
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x20000
+ MAP_TYPE = 0xf
+ MSG_CMSG_CLOEXEC = 0x40000000
+ MSG_CONFIRM = 0x800
+ MSG_CTRUNC = 0x8
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x40
+ MSG_EOR = 0x80
+ MSG_ERRQUEUE = 0x2000
+ MSG_FIN = 0x200
+ MSG_MORE = 0x8000
+ MSG_NOSIGNAL = 0x4000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_PROXY = 0x10
+ MSG_RST = 0x1000
+ MSG_SYN = 0x400
+ MSG_TRUNC = 0x20
+ MSG_TRYHARD = 0x4
+ MSG_WAITALL = 0x100
NAME_MAX = 0xff
O_ACCMODE = 0x3
O_APPEND = 0x400
@@ -423,6 +457,12 @@ const (
PACKET_RECV_OUTPUT = 0x3
PACKET_RX_RING = 0x5
PACKET_STATISTICS = 0x6
+ PROT_EXEC = 0x4
+ PROT_GROWSDOWN = 0x1000000
+ PROT_GROWSUP = 0x2000000
+ PROT_NONE = 0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
PTRACE_ARCH_PRCTL = 0x1e
PTRACE_ATTACH = 0x10
PTRACE_BTS_CLEAR = 0x2c
@@ -477,6 +517,11 @@ const (
PTRACE_SYSEMU = 0x1f
PTRACE_SYSEMU_SINGLESTEP = 0x20
PTRACE_TRACEME = 0
+ SCM_CREDENTIALS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x1d
+ SCM_TIMESTAMPING = 0x25
+ SCM_TIMESTAMPNS = 0x23
SHUT_RD = 0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
diff --git a/src/pkg/syscall/zsyscall_linux_amd64.go b/src/pkg/syscall/zsyscall_linux_amd64.go
index e08525be4d..94cdc023c2 100644
--- a/src/pkg/syscall/zsyscall_linux_amd64.go
+++ b/src/pkg/syscall/zsyscall_linux_amd64.go
@@ -1089,3 +1089,20 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
errno = int(e1)
return
}
+
+// 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
+}