@@ -18,8 +18,10 @@ import (
18
18
"bufio"
19
19
"context"
20
20
"encoding/json"
21
+ "fmt"
21
22
"io"
22
23
"net"
24
+ "os"
23
25
"sync"
24
26
"sync/atomic"
25
27
"time"
@@ -34,6 +36,9 @@ type SocketMonitor struct {
34
36
// QEMU version reported by a connected monitor socket.
35
37
Version * Version
36
38
39
+ // QEMU QMP capabiltiies reported by a connected monitor socket.
40
+ Capabilities []string
41
+
37
42
// Underlying connection
38
43
c net.Conn
39
44
@@ -119,6 +124,7 @@ func (mon *SocketMonitor) Connect() error {
119
124
return err
120
125
}
121
126
mon .Version = & ban .QMP .Version
127
+ mon .Capabilities = ban .QMP .Capabilities
122
128
123
129
// Issue capabilities handshake
124
130
cmd := Command {Execute : qmpCapabilities }
@@ -194,13 +200,45 @@ func (mon *SocketMonitor) listen(r io.Reader, events chan<- Event, stream chan<-
194
200
// For a list of available QAPI commands, see:
195
201
// http://git.qemu.org/?p=qemu.git;a=blob;f=qapi-schema.json;hb=HEAD
196
202
func (mon * SocketMonitor ) Run (command []byte ) ([]byte , error ) {
203
+ // Just call RunWithFile with no file
204
+ return mon .RunWithFile (command , nil )
205
+ }
206
+
207
+ // RunWithFile behaves like Run but allows for passing a file through out-of-band data.
208
+ func (mon * SocketMonitor ) RunWithFile (command []byte , file * os.File ) ([]byte , error ) {
197
209
// Only allow a single command to be run at a time to ensure that responses
198
210
// to a command cannot be mixed with responses from another command
199
211
mon .mu .Lock ()
200
212
defer mon .mu .Unlock ()
201
213
202
- if _ , err := mon .c .Write (command ); err != nil {
203
- return nil , err
214
+ if file == nil {
215
+ // Just send a normal command through.
216
+ if _ , err := mon .c .Write (command ); err != nil {
217
+ return nil , err
218
+ }
219
+ } else {
220
+ unixConn , ok := mon .c .(* net.UnixConn )
221
+ if ! ok {
222
+ return nil , fmt .Errorf ("RunWithFile only works with unix monitor sockets" )
223
+ }
224
+
225
+ oobSupported := false
226
+ for _ , capability := range mon .Capabilities {
227
+ if capability == "oob" {
228
+ oobSupported = true
229
+ break
230
+ }
231
+ }
232
+
233
+ if ! oobSupported {
234
+ return nil , fmt .Errorf ("The QEMU server doesn't support oob (needed for RunWithFile)" )
235
+ }
236
+
237
+ // Send the command along with the file descriptor.
238
+ oob := getUnixRights (file )
239
+ if _ , _ , err := unixConn .WriteMsgUnix (command , oob , nil ); err != nil {
240
+ return nil , err
241
+ }
204
242
}
205
243
206
244
// Wait for a response or error to our command
@@ -224,6 +262,7 @@ func (mon *SocketMonitor) Run(command []byte) ([]byte, error) {
224
262
// banner is a wrapper type around a Version.
225
263
type banner struct {
226
264
QMP struct {
265
+ Capabilities []string `json:"capabilities"`
227
266
Version Version `json:"version"`
228
267
} `json:"QMP"`
229
268
}
0 commit comments