| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 |
- // Package msgx calls xnu's private batched socket calls, sendmsg_x and recvmsg_x, which move many datagrams per
- // syscall. They are not public API, so a kernel or sandbox may refuse them; callers fall back to one datagram per
- // syscall when Unsupported reports that.
- package msgx
- import (
- "syscall"
- "unsafe"
- "golang.org/x/sys/unix"
- )
- // Batch is the most messages the callers hand one sendmsg_x or recvmsg_x call.
- const Batch = 64
- // Hdr mirrors xnu's struct msghdr_x (bsd/sys/socket_private.h), which the SDK doesn't ship. recvmsg_x reports each
- // message's length in Datalen rather than in its return value.
- type Hdr struct {
- Name *byte
- Namelen uint32
- Iov *unix.Iovec
- Iovlen int32
- Control *byte
- Controllen uint32
- Flags int32
- Datalen uint64
- }
- // Send passes hdrs to sendmsg_x on fd and returns how many messages the kernel took. EINTR is retried.
- func Send(fd uintptr, hdrs []Hdr) (int, syscall.Errno) {
- return call(unix.SYS_SENDMSG_X, fd, hdrs)
- }
- // Recv passes hdrs to recvmsg_x on fd and returns how many messages it filled. EINTR is retried.
- func Recv(fd uintptr, hdrs []Hdr) (int, syscall.Errno) {
- return call(unix.SYS_RECVMSG_X, fd, hdrs)
- }
- func call(trap, fd uintptr, hdrs []Hdr) (int, syscall.Errno) {
- if len(hdrs) == 0 {
- return 0, syscall.EINVAL
- }
- for {
- r, _, errno := unix.Syscall6(trap, fd, uintptr(unsafe.Pointer(&hdrs[0])), uintptr(len(hdrs)), 0, 0, 0)
- switch errno {
- case 0:
- return int(r), 0
- case syscall.EINTR:
- default:
- return 0, errno
- }
- }
- }
- // Unsupported reports whether errno means the kernel or a sandbox refuses the private calls.
- func Unsupported(errno syscall.Errno) bool {
- return errno == syscall.ENOSYS || errno == syscall.EPERM || errno == syscall.EOPNOTSUPP
- }
|