| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- //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
- }
|