rpcout.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. // Copyright 2016 VMware, Inc. All Rights Reserved.
  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. package rpcout
  15. import (
  16. "errors"
  17. "fmt"
  18. "github.com/vmware/vmw-guestinfo/message"
  19. )
  20. // ErrRpciFormat represents an invalid result format
  21. var ErrRpciFormat = errors.New("invalid format for RPCI command result")
  22. const rpciProtocolNum uint32 = 0x49435052
  23. // SendOne is a command-oriented wrapper for SendOneRaw
  24. func SendOne(format string, a ...interface{}) (reply []byte, ok bool, err error) {
  25. request := fmt.Sprintf(format, a...)
  26. return SendOneRaw([]byte(request))
  27. }
  28. // SendOneRaw uses a throw-away RPCOut to send a request
  29. func SendOneRaw(request []byte) (reply []byte, ok bool, err error) {
  30. out := &RPCOut{}
  31. if err = out.Start(); err != nil {
  32. return
  33. }
  34. if reply, ok, err = out.Send(request); err != nil {
  35. return
  36. }
  37. if err = out.Stop(); err != nil {
  38. return
  39. }
  40. return
  41. }
  42. // RPCOut is an ougoing connection from the VM to the hypervisor
  43. type RPCOut struct {
  44. channel *message.Channel
  45. }
  46. // Start opens the connection
  47. func (out *RPCOut) Start() error {
  48. channel, err := message.NewChannel(rpciProtocolNum)
  49. if err != nil {
  50. return err
  51. }
  52. out.channel = channel
  53. return nil
  54. }
  55. // Stop closes the connection
  56. func (out *RPCOut) Stop() error {
  57. err := out.channel.Close()
  58. out.channel = nil
  59. return err
  60. }
  61. // Send emits a request and receives a response
  62. func (out *RPCOut) Send(request []byte) (reply []byte, ok bool, err error) {
  63. if err = out.channel.Send(request); err != nil {
  64. return
  65. }
  66. var resp []byte
  67. if resp, err = out.channel.Receive(); err != nil {
  68. return
  69. }
  70. switch string(resp[:2]) {
  71. case "0 ":
  72. reply = resp[2:]
  73. case "1 ":
  74. reply = resp[2:]
  75. ok = true
  76. default:
  77. err = ErrRpciFormat
  78. }
  79. return
  80. }