mirror of
https://github.com/slackhq/nebula.git
synced 2026-11-15 14:26:57 +01:00
78 lines
2.3 KiB
Go
78 lines
2.3 KiB
Go
//go:build !ios
|
|
|
|
package msgx
|
|
|
|
import (
|
|
"sync"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
// dlsym is public libSystem API, imported the way x/sys/unix imports its libSystem stubs. The local name is
|
|
// distinct from runtime/race's dlsym import.
|
|
//
|
|
//go:cgo_import_dynamic msgx_dlsym dlsym "/usr/lib/libSystem.B.dylib"
|
|
|
|
// dlsymTrampolineAddr is the address of msgx_darwin.s's jump to dlsym.
|
|
var dlsymTrampolineAddr uintptr
|
|
|
|
// syscall6X calls the C function at fn on the system stack and returns errno when it returns a 64-bit -1.
|
|
// It is how x/sys/unix calls libSystem, and the runtime keeps it linkable for that.
|
|
//
|
|
//go:linkname syscall6X syscall.syscall6X
|
|
func syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
|
|
|
// rtldDefault is dlfcn.h's RTLD_DEFAULT, ((void *)-2): search every image loaded in the process.
|
|
const rtldDefault = ^uintptr(1)
|
|
|
|
var (
|
|
sendmsgXName = []byte("sendmsg_x\x00")
|
|
recvmsgXName = []byte("recvmsg_x\x00")
|
|
)
|
|
|
|
type funcs struct {
|
|
sendmsgX uintptr
|
|
recvmsgX uintptr
|
|
}
|
|
|
|
var resolve = sync.OnceValue(func() funcs {
|
|
return funcs{sendmsgX: lookup(sendmsgXName), recvmsgX: lookup(recvmsgXName)}
|
|
})
|
|
|
|
// lookup returns the address of the NUL-terminated C symbol name, or 0 when no loaded image exports it.
|
|
func lookup(name []byte) uintptr {
|
|
p, _, _ := syscall6X(dlsymTrampolineAddr, rtldDefault, uintptr(unsafe.Pointer(&name[0])), 0, 0, 0, 0)
|
|
return p
|
|
}
|
|
|
|
// Available reports whether libSystem exports both sendmsg_x and recvmsg_x. When it is false, Send and Recv
|
|
// return ENOSYS.
|
|
func Available() bool {
|
|
f := resolve()
|
|
return f.sendmsgX != 0 && f.recvmsgX != 0
|
|
}
|
|
|
|
// Send passes hdrs to sendmsg_x on fd and returns how many messages the kernel took.
|
|
func Send(fd uintptr, hdrs []Hdr, flags int) (int, syscall.Errno) {
|
|
return call(resolve().sendmsgX, fd, hdrs, flags)
|
|
}
|
|
|
|
// Recv passes hdrs to recvmsg_x on fd and returns how many messages it filled.
|
|
func Recv(fd uintptr, hdrs []Hdr, flags int) (int, syscall.Errno) {
|
|
return call(resolve().recvmsgX, fd, hdrs, flags)
|
|
}
|
|
|
|
func call(fn, fd uintptr, hdrs []Hdr, flags int) (int, syscall.Errno) {
|
|
if fn == 0 {
|
|
return 0, syscall.ENOSYS
|
|
}
|
|
if len(hdrs) == 0 {
|
|
return 0, syscall.EINVAL
|
|
}
|
|
r, _, errno := syscall6X(fn, fd, uintptr(unsafe.Pointer(&hdrs[0])), uintptr(len(hdrs)), uintptr(flags), 0, 0)
|
|
if errno != 0 {
|
|
return 0, errno
|
|
}
|
|
return int(r), 0
|
|
}
|