Skip to content

Commit 152a153

Browse files
authored
[qmp] Add RunWithFile to socket client (digitalocean#169)
* qmp/socket: Add capabilities tracking * qmp/socket: Add new RunWithFile function Signed-off-by: Stéphane Graber <[email protected]>
1 parent d361e7b commit 152a153

File tree

5 files changed

+97
-2
lines changed

5 files changed

+97
-2
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ go 1.15
55
require (
66
github.com/digitalocean/go-libvirt v0.0.0-20201209184759-e2a69bcd5bd1
77
github.com/fatih/camelcase v1.0.0
8+
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4
89
)

go.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
2222
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
2323
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
2424
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
25+
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
2526
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
27+
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
28+
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
2629
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
2730
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
2831
golang.org/x/tools v0.0.0-20200711155855-7342f9734a7d h1:F3OmlXCzYtG9YE6tXDnUOlJBzVzHF8EcmZ1yTJlcgIk=

qmp/socket.go

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ import (
1818
"bufio"
1919
"context"
2020
"encoding/json"
21+
"fmt"
2122
"io"
2223
"net"
24+
"os"
2325
"sync"
2426
"sync/atomic"
2527
"time"
@@ -34,6 +36,9 @@ type SocketMonitor struct {
3436
// QEMU version reported by a connected monitor socket.
3537
Version *Version
3638

39+
// QEMU QMP capabiltiies reported by a connected monitor socket.
40+
Capabilities []string
41+
3742
// Underlying connection
3843
c net.Conn
3944

@@ -119,6 +124,7 @@ func (mon *SocketMonitor) Connect() error {
119124
return err
120125
}
121126
mon.Version = &ban.QMP.Version
127+
mon.Capabilities = ban.QMP.Capabilities
122128

123129
// Issue capabilities handshake
124130
cmd := Command{Execute: qmpCapabilities}
@@ -194,13 +200,45 @@ func (mon *SocketMonitor) listen(r io.Reader, events chan<- Event, stream chan<-
194200
// For a list of available QAPI commands, see:
195201
// http://git.qemu.org/?p=qemu.git;a=blob;f=qapi-schema.json;hb=HEAD
196202
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) {
197209
// Only allow a single command to be run at a time to ensure that responses
198210
// to a command cannot be mixed with responses from another command
199211
mon.mu.Lock()
200212
defer mon.mu.Unlock()
201213

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+
}
204242
}
205243

206244
// Wait for a response or error to our command
@@ -224,6 +262,7 @@ func (mon *SocketMonitor) Run(command []byte) ([]byte, error) {
224262
// banner is a wrapper type around a Version.
225263
type banner struct {
226264
QMP struct {
265+
Capabilities []string `json:"capabilities"`
227266
Version Version `json:"version"`
228267
} `json:"QMP"`
229268
}

qmp/socket_unix.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2016 The go-qemu Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// +build !windows
16+
17+
package qmp
18+
19+
import (
20+
"os"
21+
22+
"golang.org/x/sys/unix"
23+
)
24+
25+
func getUnixRights(file *os.File) []byte {
26+
return unix.UnixRights(int(file.Fd()))
27+
}

qmp/socket_windows.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2016 The go-qemu Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// +build windows
16+
17+
package qmp
18+
19+
import (
20+
"os"
21+
)
22+
23+
func getUnixRights(file *os.File) []byte {
24+
return nil
25+
}

0 commit comments

Comments
 (0)