Skip to content

Golang support for launchd socket activation (launch_activate_socket) without cgo

License

Notifications You must be signed in to change notification settings

bored-engineer/go-launchd

Repository files navigation

go-launchd Go Reference Test Workflow

Golang support for macOS (Darwin) launchd socket activation (launch_activate_socket) without cgo.

How it works

Using a similar technique as the crypto/x509 package and golang.org/x/sys/unix package it is possible to import the launch_activate_socket function from libxpc.dylib at runtime via the go:cgo_import_dynamic directive:

// launch_activate_socket is defined in libxpc.dylib
var libxpc_launch_activate_socket_trampoline_addr uintptr

//go:cgo_import_dynamic libxpc_launch_activate_socket launch_activate_socket "/usr/lib/system/libxpc.dylib"

This must be combined with a golang assembly file (libxpc.s) to populate the "trampoline" variable with a pointer to the relevant function:

TEXT libxpc_launch_activate_socket_trampoline<>(SB),NOSPLIT,$0-0
    JMP	libxpc_launch_activate_socket(SB)

GLOBL	·libxpc_launch_activate_socket_trampoline_addr(SB), RODATA, $8
DATA	·libxpc_launch_activate_socket_trampoline_addr(SB)/8, $libxpc_launch_activate_socket_trampoline<>(SB)

Finally by linking the internal syscall.syscall function we are able to invoke the launch_activate_socket function:

// Implemented in the runtime package (runtime/sys_darwin.go)
func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)

//go:linkname syscall_syscall syscall.syscall

The remaining logic is primarily implemented in libxpc.go to convert from C structures into Golang equivalents.

Usage

See also the example/ directory for the associated launchd job definition (plist):

package main

import launchd "github.com/bored-engineer/go-launchd"

func main() {
	l, err := launchd.Activate("Listeners")
	if err != nil {
		log.Fatalf("launchd.Socket failed: %s", err)
	}
	for {
		conn, err := l.Accept()
		if err != nil {
			log.Printf("(net.Listener).Accept failed: %s", err)
			continue
		}
		go func(conn net.Conn) {
			defer conn.Close()
			io.Copy(conn, conn)
		}(conn)
	}
}

About

Golang support for launchd socket activation (launch_activate_socket) without cgo

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published