internal/pipewire: implement SecurityContext::Create
All checks were successful
Test / Create distribution (push) Successful in 37s
Test / Sandbox (push) Successful in 2m18s
Test / Hakurei (push) Successful in 3m18s
Test / Hpkg (push) Successful in 4m12s
Test / Sandbox (race detector) (push) Successful in 4m19s
Test / Hakurei (race detector) (push) Successful in 2m58s
Test / Flake checks (push) Successful in 1m36s

This is finally the thing we are after.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2025-11-29 16:08:31 +09:00
parent 5a5c4705dd
commit 90d7f62c69
5 changed files with 122 additions and 37 deletions

View File

@@ -314,19 +314,13 @@ func TestHeader(t *testing.T) {
Size: 0x68, Sequence: 43, FileCount: 0, Size: 0x68, Sequence: 43, FileCount: 0,
}, nil}, }, nil},
{"PW_SECURITY_CONTEXT_METHOD_CREATE", []byte{ /* sendmsg 2 */
// Id
3, 0, 0, 0, {"PW_SECURITY_CONTEXT_METHOD_CREATE", samplePWContainer[6][0][0], pipewire.Header{
// size ID: 3,
0xd8, 0, 0, Opcode: pipewire.PW_SECURITY_CONTEXT_METHOD_CREATE,
// opcode Size: 0xd8, Sequence: 5, FileCount: 2,
1, }, nil},
// seq
5, 0, 0, 0,
// n_fds
2, 0, 0, 0,
}, pipewire.Header{ID: 3, Opcode: pipewire.PW_SECURITY_CONTEXT_METHOD_CREATE,
Size: 0xd8, Sequence: 5, FileCount: 2}, nil},
{"PW_SECURITY_CONTEXT_METHOD_NUM", []byte{ {"PW_SECURITY_CONTEXT_METHOD_NUM", []byte{
// Id // Id

View File

@@ -356,30 +356,6 @@ const (
PW_KEY_PROFILER_NAME = "profiler.name" PW_KEY_PROFILER_NAME = "profiler.name"
) )
/* pipewire/extensions/security-context.h */
const (
PW_TYPE_INTERFACE_SecurityContext = PW_TYPE_INFO_INTERFACE_BASE + "SecurityContext"
PW_SECURITY_CONTEXT_PERM_MASK = PW_PERM_RWX
PW_VERSION_SECURITY_CONTEXT = 3
PW_EXTENSION_MODULE_SECURITY_CONTEXT = PIPEWIRE_MODULE_PREFIX + "module-security-context"
)
const (
PW_SECURITY_CONTEXT_EVENT_NUM = iota
PW_VERSION_SECURITY_CONTEXT_EVENTS = 0
)
const (
PW_SECURITY_CONTEXT_METHOD_ADD_LISTENER = iota
PW_SECURITY_CONTEXT_METHOD_CREATE
PW_SECURITY_CONTEXT_METHOD_NUM
PW_VERSION_SECURITY_CONTEXT_METHODS = 0
)
/* pipewire/type.h */ /* pipewire/type.h */
const ( const (

View File

@@ -30,6 +30,9 @@ type (
String = string String = string
// Bytes is a byte slice representing SPA_TYPE_Bytes. // Bytes is a byte slice representing SPA_TYPE_Bytes.
Bytes = []byte Bytes = []byte
// A Fd is a signed integer value representing SPA_TYPE_Fd.
Fd Long
) )
const ( const (
@@ -49,6 +52,9 @@ const (
SizeInt Word = 4 SizeInt Word = 4
// SizeLong is the fixed, unpadded size of a [SPA_TYPE_Long] value. // SizeLong is the fixed, unpadded size of a [SPA_TYPE_Long] value.
SizeLong Word = 8 SizeLong Word = 8
// SizeFd is the fixed, unpadded size of a [SPA_TYPE_Fd] value.
SizeFd = SizeLong
) )
/* Basic types */ /* Basic types */
@@ -176,6 +182,15 @@ func marshalValueAppend(data []byte, v reflect.Value) ([]byte, error) {
// marshalValueAppendRaw implements [MarshalAppend] on [reflect.Value] without the size prefix. // marshalValueAppendRaw implements [MarshalAppend] on [reflect.Value] without the size prefix.
func marshalValueAppendRaw(data []byte, v reflect.Value) ([]byte, error) { func marshalValueAppendRaw(data []byte, v reflect.Value) ([]byte, error) {
if v.CanInterface() {
switch c := v.Interface().(type) {
case Fd:
data = binary.NativeEndian.AppendUint32(data, SPA_TYPE_Fd)
data = binary.NativeEndian.AppendUint64(data, uint64(c))
return data, nil
}
}
switch v.Kind() { switch v.Kind() {
case reflect.Uint32: case reflect.Uint32:
data = binary.NativeEndian.AppendUint32(data, SPA_TYPE_Id) data = binary.NativeEndian.AppendUint32(data, SPA_TYPE_Id)
@@ -312,6 +327,16 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error {
*wireSizeP, err = u.UnmarshalPOD(data) *wireSizeP, err = u.UnmarshalPOD(data)
return err return err
} }
switch v.Interface().(type) {
case Fd:
*wireSizeP = SizeFd
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Fd, wireSizeP); err != nil {
return err
}
v.SetInt(int64(binary.NativeEndian.Uint64(data)))
return nil
}
} }
switch v.Kind() { switch v.Kind() {

View File

@@ -0,0 +1,69 @@
package pipewire
/* pipewire/extensions/security-context.h */
const (
PW_TYPE_INTERFACE_SecurityContext = PW_TYPE_INFO_INTERFACE_BASE + "SecurityContext"
PW_SECURITY_CONTEXT_PERM_MASK = PW_PERM_RWX
PW_VERSION_SECURITY_CONTEXT = 3
PW_EXTENSION_MODULE_SECURITY_CONTEXT = PIPEWIRE_MODULE_PREFIX + "module-security-context"
)
const (
PW_SECURITY_CONTEXT_EVENT_NUM = iota
PW_VERSION_SECURITY_CONTEXT_EVENTS = 0
)
const (
PW_SECURITY_CONTEXT_METHOD_ADD_LISTENER = iota
PW_SECURITY_CONTEXT_METHOD_CREATE
PW_SECURITY_CONTEXT_METHOD_NUM
PW_VERSION_SECURITY_CONTEXT_METHODS = 0
)
// SecurityContextCreate is sent to create a new security context.
//
// Creates a new security context with a socket listening FD.
// PipeWire will accept new client connections on listen_fd.
//
// listen_fd must be ready to accept new connections when this
// request is sent by the client. In other words, the client must
// call bind(2) and listen(2) before sending the FD.
//
// close_fd is a FD closed by the client when PipeWire should stop
// accepting new connections on listen_fd.
//
// PipeWire must continue to accept connections on listen_fd when
// the client which created the security context disconnects.
//
// After sending this request, closing listen_fd and close_fd
// remains the only valid operation on them.
type SecurityContextCreate struct {
// The offset in the SCM_RIGHTS msg_control message to
// the fd to listen on for new connections.
ListenFd Fd
// The offset in the SCM_RIGHTS msg_control message to
// the fd used to stop listening.
CloseFd Fd
// Extra properties. These will be copied on the client
// that connects through this context.
Properties *SPADict `json:"props"`
}
// Size satisfies [KnownSize] with a value computed at runtime.
func (c *SecurityContextCreate) Size() Word {
return SizePrefix +
Size(SizeFd) +
Size(SizeFd) +
c.Properties.Size()
}
// MarshalBinary satisfies [encoding.BinaryMarshaler] via [Marshal].
func (c *SecurityContextCreate) MarshalBinary() ([]byte, error) { return Marshal(c) }
// UnmarshalBinary satisfies [encoding.BinaryUnmarshaler] via [Unmarshal].
func (c *SecurityContextCreate) UnmarshalBinary(data []byte) error { return Unmarshal(data, c) }

View File

@@ -0,0 +1,21 @@
package pipewire_test
import (
"testing"
"hakurei.app/internal/pipewire"
)
func TestSecurityContextCreate(t *testing.T) {
t.Parallel()
encodingTestCases[pipewire.SecurityContextCreate, *pipewire.SecurityContextCreate]{
{"sample", samplePWContainer[6][0][1], pipewire.SecurityContextCreate{
ListenFd: 1 /* 21: duplicated from listen_fd */, CloseFd: 0, /* 20: duplicated from close_fd */
Properties: &pipewire.SPADict{
{Key: "pipewire.sec.engine", Value: "org.flatpak"},
{Key: "pipewire.access", Value: "restricted"},
},
}, nil},
}.run(t)
}