-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathqmp.go
120 lines (92 loc) · 2.58 KB
/
qmp.go
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
113
114
115
116
117
118
119
120
package qmp
import (
"bufio"
"encoding/json"
"fmt"
"net"
"strings"
)
// Open creates a connection to QMP at the specified address using the named protocol
// Protocol can be tcp or unix
func Open(proto, addr string) (Session, error) {
var s Session
c, err := net.Dial(proto, addr)
if err != nil {
return s, err
}
s.c = c
var g GreetingMessage
err = json.NewDecoder(c).Decode(&g)
if err != nil {
return s, fmt.Errorf("qmp: decode json greeting: %s", err)
}
s.Greeting = g
_, err = s.Command("qmp_capabilities", nil)
if err != nil {
return s, err
}
return s, nil
}
// Close closes the connection
func (s Session) Close() error {
return s.c.Close()
}
// Command sends a command and returns the response from QEMU.
func (s Session) Command(command string, arguments map[string]interface{}) (JsonValue, error) {
cmd := make(JsonObject)
cmd["execute"] = command
if arguments != nil {
cmd["arguments"] = arguments
}
err := json.NewEncoder(s.c).Encode(cmd)
if err != nil {
return nil, fmt.Errorf("qmp: encode json: %s", err)
}
t, data, err := s.read()
if err != nil {
return nil, err
}
if t == MessageTypeSuccess {
var m SuccessMessage
err := json.Unmarshal(data, &m)
if err != nil {
return nil, fmt.Errorf("qmp: decode json error: %s", err)
}
return m.Return, nil
} else if t == MessageTypeError {
var e ErrorMessage
err := json.Unmarshal(data, &e)
if err != nil {
return nil, fmt.Errorf("qmp: decode json error: %s", err)
}
return nil, fmt.Errorf("qmp error %s: %s", e.Error.Class, e.Error.Desc)
}
return nil, fmt.Errorf("qmp: unknown message")
}
// HumanMonitorCommand sends a HMP command to QEMU via the QMP protocol
func (s Session) HumanMonitorCommand(command string) (JsonValue, error) {
return s.Command("human-monitor-command", map[string]interface{}{"command-line": command})
}
func (s *Session) read() (MessageType, []byte, error) {
scanner := bufio.NewScanner(s.c)
for scanner.Scan() {
str := scanner.Text()
if strings.Contains(str, "\"return\"") {
return MessageTypeSuccess, []byte(str), nil
} else if strings.Contains(str, "\"error\"") {
return MessageTypeError, []byte(str), nil
} else if strings.Contains(str, "\"event\"") {
var e AsyncMessage
err := json.Unmarshal([]byte(str), &e)
if err != nil {
return 0, nil, fmt.Errorf("qmp: json: failed to decode event: %s", err)
}
s.AsyncMessages = append(s.AsyncMessages, e)
continue
}
}
if err := scanner.Err(); err != nil {
return 0, nil, fmt.Errorf("qmp: failed to read line: %s", err)
}
return 0, nil, fmt.Errorf("qmp: invalid response")
}