mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
- fork go-wayland/client and modify to make it thread-safe internally - use sync.Map and atomic values in many places to cut down on mutex boilerplate - do not create extworkspace client unless explicitly requested
121 lines
2.6 KiB
Go
121 lines
2.6 KiB
Go
package client
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/unix"
|
|
|
|
_ "unsafe"
|
|
)
|
|
|
|
var oobSpace = unix.CmsgSpace(4)
|
|
|
|
func (ctx *Context) ReadMsg() (senderID uint32, opcode uint32, fd int, msg []byte, err error) {
|
|
fd = -1
|
|
|
|
oob := make([]byte, oobSpace)
|
|
header := make([]byte, 8)
|
|
|
|
n, oobn, _, _, err := ctx.conn.ReadMsgUnix(header, oob)
|
|
if err != nil {
|
|
return senderID, opcode, fd, msg, err
|
|
}
|
|
if n != 8 {
|
|
return senderID, opcode, fd, msg, fmt.Errorf("ctx.ReadMsg: incorrect number of bytes read for header (n=%d)", n)
|
|
}
|
|
|
|
if oobn > 0 {
|
|
fds, err := getFdsFromOob(oob, oobn, "header")
|
|
if err != nil {
|
|
return senderID, opcode, fd, msg, fmt.Errorf("ctx.ReadMsg: %w", err)
|
|
}
|
|
|
|
if len(fds) > 0 {
|
|
fd = fds[0]
|
|
}
|
|
}
|
|
|
|
senderID = Uint32(header[:4])
|
|
opcodeAndSize := Uint32(header[4:8])
|
|
opcode = opcodeAndSize & 0xffff
|
|
size := opcodeAndSize >> 16
|
|
|
|
msgSize := int(size) - 8
|
|
if msgSize == 0 {
|
|
return senderID, opcode, fd, nil, nil
|
|
}
|
|
|
|
msg = make([]byte, msgSize)
|
|
|
|
if fd == -1 {
|
|
// if something was read before, then zero it out
|
|
if oobn > 0 {
|
|
oob = make([]byte, oobSpace)
|
|
}
|
|
|
|
n, oobn, _, _, err = ctx.conn.ReadMsgUnix(msg, oob)
|
|
} else {
|
|
n, err = ctx.conn.Read(msg)
|
|
}
|
|
if err != nil {
|
|
return senderID, opcode, fd, msg, fmt.Errorf("ctx.ReadMsg: %w", err)
|
|
}
|
|
if n != msgSize {
|
|
return senderID, opcode, fd, msg, fmt.Errorf("ctx.ReadMsg: incorrect number of bytes read for msg (n=%d, msgSize=%d)", n, msgSize)
|
|
}
|
|
|
|
if fd == -1 && oobn > 0 {
|
|
fds, err := getFdsFromOob(oob, oobn, "msg")
|
|
if err != nil {
|
|
return senderID, opcode, fd, msg, fmt.Errorf("ctx.ReadMsg: %w", err)
|
|
}
|
|
|
|
if len(fds) > 0 {
|
|
fd = fds[0]
|
|
}
|
|
}
|
|
|
|
return senderID, opcode, fd, msg, nil
|
|
}
|
|
|
|
func getFdsFromOob(oob []byte, oobn int, source string) ([]int, error) {
|
|
if oobn > len(oob) {
|
|
return nil, fmt.Errorf("getFdsFromOob: incorrect number of bytes read from %s for oob (oobn=%d)", source, oobn)
|
|
}
|
|
scms, err := unix.ParseSocketControlMessage(oob)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("getFdsFromOob: unable to parse control message from %s: %w", source, err)
|
|
}
|
|
|
|
var fdsRet []int
|
|
for _, scm := range scms {
|
|
fds, err := unix.ParseUnixRights(&scm)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("getFdsFromOob: unable to parse unix rights from %s: %w", source, err)
|
|
}
|
|
|
|
fdsRet = append(fdsRet, fds...)
|
|
}
|
|
|
|
return fdsRet, nil
|
|
}
|
|
|
|
func Uint32(src []byte) uint32 {
|
|
_ = src[3]
|
|
return *(*uint32)(unsafe.Pointer(&src[0]))
|
|
}
|
|
|
|
func String(src []byte) string {
|
|
idx := bytes.IndexByte(src, 0)
|
|
src = src[:idx:idx]
|
|
return *(*string)(unsafe.Pointer(&src))
|
|
}
|
|
|
|
func Fixed(src []byte) float64 {
|
|
_ = src[3]
|
|
fx := *(*int32)(unsafe.Pointer(&src[0]))
|
|
return fixedToFloat64(fx)
|
|
}
|