File: request.go

package info (click to toggle)
golang-github-dkolbly-wl 0.0~git20180220.b06f57e-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 336 kB
  • sloc: makefile: 3
file content (112 lines) | stat: -rw-r--r-- 2,172 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package wl

import (
	"errors"
	"net"
	"syscall"
)

type Request struct {
	pid    ProxyId
	opcode uint32
	data   []byte
	oob    []byte
}

func (context *Context) SendRequest(proxy Proxy, opcode uint32, args ...interface{}) (err error) {
	req := Request{
		pid:    proxy.Id(),
		opcode: opcode,
	}

	for _, arg := range args {
		req.Write(arg)
	}

	return writeRequest(context.conn, req)
}

func (r *Request) Write(arg interface{}) {
	switch t := arg.(type) {
	case Proxy:
		r.PutProxy(t)
	case uint32:
		r.PutUint32(t)
	case int32:
		r.PutInt32(t)
	case float32:
		r.PutFloat32(t)
	case string:
		r.PutString(t)
	case []int32:
		r.PutArray(t)
	case uintptr:
		r.PutFd(t)
	default:
		panic("Invalid Wayland request parameter type.")
	}
}

func (r *Request) PutUint32(u uint32) {
	buf := bytePool.Take(4)
	order.PutUint32(buf, u)
	r.data = append(r.data, buf...)
}

func (r *Request) PutProxy(p Proxy) {
	r.PutUint32(uint32(p.Id()))
}

func (r *Request) PutInt32(i int32) {
	r.PutUint32(uint32(i))
}

func (r *Request) PutFloat32(f float32) {
	fx := float64ToFixed(float64(f))
	r.PutUint32(uint32(fx))
}

func (r *Request) PutString(s string) {
	tail := 4 - (len(s) & 0x3)
	r.PutUint32(uint32(len(s) + tail))
	r.data = append(r.data, []byte(s)...)
	// if padding required
	if tail > 0 {
		padding := make([]byte, tail)
		r.data = append(r.data, padding...)
	}
}

func (r *Request) PutArray(a []int32) {
	r.PutUint32(uint32(len(a)))
	for _, e := range a {
		r.PutUint32(uint32(e))
	}
}

func (r *Request) PutFd(fd uintptr) {
	rights := syscall.UnixRights(int(fd))
	r.oob = append(r.oob, rights...)
}

func writeRequest(conn *net.UnixConn, r Request) error {
	var header []byte
	// calculate message total size
	size := uint32(len(r.data) + 8)
	buf := make([]byte, 4)
	order.PutUint32(buf, uint32(r.pid))
	header = append(header, buf...)
	order.PutUint32(buf, uint32(size<<16|r.opcode&0x0000ffff))
	header = append(header, buf...)

	d, c, err := conn.WriteMsgUnix(append(header, r.data...), r.oob, nil)
	if err != nil {
		return err
	}
	if c != len(r.oob) || d != (len(header)+len(r.data)) {
		return errors.New("WriteMsgUnix failed")
	}
	bytePool.Give(r.data)

	return nil
}