tunnel.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // Copyright 2019 Yunion
  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 guac
  15. import (
  16. "fmt"
  17. "io"
  18. "net"
  19. "time"
  20. "yunion.io/x/log"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/gotypes"
  23. )
  24. const (
  25. TunnerClose = errors.Error("TunnerClose")
  26. InvalidInstruction = errors.Error("InvalidInstruction")
  27. )
  28. type GuacamoleTunnel struct {
  29. opts *GuacOptions
  30. conn net.Conn
  31. instructs chan *Instruction
  32. err chan error
  33. stopChan chan bool
  34. isStart bool
  35. }
  36. func (self *GuacamoleTunnel) Write(data []byte) (int, error) {
  37. return self.conn.Write(data)
  38. }
  39. func (self *GuacamoleTunnel) ReadOne() (*Instruction, error) {
  40. for {
  41. select {
  42. case instruct := <-self.instructs:
  43. if gotypes.IsNil(instruct) {
  44. return nil, InvalidInstruction
  45. }
  46. return instruct, nil
  47. case <-time.After(1 * time.Second):
  48. }
  49. }
  50. }
  51. func (self *GuacamoleTunnel) Start() error {
  52. return self.start()
  53. }
  54. func (self *GuacamoleTunnel) start() error {
  55. if self.isStart {
  56. return nil
  57. }
  58. go func() {
  59. self.isStart = true
  60. self.instructs = make(chan *Instruction, 10)
  61. self.stopChan = make(chan bool)
  62. self.err = make(chan error)
  63. var buf []byte = make([]byte, 4*1024*1024)
  64. var left []byte = []byte{}
  65. for {
  66. select {
  67. case <-self.stopChan:
  68. close(self.instructs)
  69. return
  70. default:
  71. n, err := self.conn.Read(buf)
  72. if err != nil && err != io.EOF {
  73. self.err <- errors.Wrapf(err, "Read")
  74. return
  75. }
  76. instructions, _left, err := parse(append(left, buf[:n]...))
  77. if err != nil {
  78. self.err <- errors.Wrapf(err, "parse instruct")
  79. return
  80. }
  81. left = _left
  82. for i := range instructions {
  83. self.instructs <- instructions[i]
  84. }
  85. }
  86. }
  87. }()
  88. return nil
  89. }
  90. func (self *GuacamoleTunnel) Stop() {
  91. defer self.conn.Close()
  92. self.err <- TunnerClose
  93. self.stopChan <- true
  94. }
  95. func (self *GuacamoleTunnel) Wait() error {
  96. err := <-self.err
  97. return err
  98. }
  99. func (self *GuacamoleTunnel) Handshake() error {
  100. selectArg := self.opts.Protocol
  101. if len(self.opts.ConnectionId) > 0 {
  102. selectArg = self.opts.ConnectionId
  103. }
  104. err := self.start()
  105. if err != nil {
  106. return err
  107. }
  108. _, err = self.Write([]byte(NewInstruction("select", selectArg).String()))
  109. if err != nil {
  110. return errors.Wrapf(err, "select")
  111. }
  112. args, err := self.ReadOne()
  113. if err != nil {
  114. return errors.Wrapf(err, "ReadOne")
  115. }
  116. if args.Opcode != "args" {
  117. return errors.Wrapf(InvalidInstruction, "%v", args.String())
  118. }
  119. for i, arg := range args.Args {
  120. args.Args[i] = self.opts.Parameters[arg]
  121. }
  122. _, err = self.Write([]byte(NewInstruction("size",
  123. fmt.Sprintf("%v", self.opts.OptimalScreenWidth),
  124. fmt.Sprintf("%v", self.opts.OptimalScreenHeight),
  125. fmt.Sprintf("%v", self.opts.OptimalResolution),
  126. ).String()))
  127. if err != nil {
  128. return errors.Wrapf(err, "set size")
  129. }
  130. _, err = self.Write([]byte(NewInstruction("audio", self.opts.AudioMimetypes...).String()))
  131. if err != nil {
  132. return errors.Wrapf(err, "set audio")
  133. }
  134. _, err = self.Write([]byte(NewInstruction("video", self.opts.VideoMimetypes...).String()))
  135. if err != nil {
  136. return errors.Wrapf(err, "set video")
  137. }
  138. _, err = self.Write([]byte(NewInstruction("image", self.opts.ImageMimetypes...).String()))
  139. if err != nil {
  140. return errors.Wrapf(err, "set image")
  141. }
  142. _, err = self.Write([]byte(NewInstruction("connect", args.Args...).String()))
  143. if err != nil {
  144. return errors.Wrapf(err, "connect %s", args.Args)
  145. }
  146. ready, err := self.ReadOne()
  147. if err != nil {
  148. return errors.Wrapf(err, "read ready")
  149. }
  150. if ready.Opcode != "ready" {
  151. return errors.Wrapf(InvalidInstruction, "%v", ready.String())
  152. }
  153. if len(ready.Args) == 0 {
  154. return fmt.Errorf("no connection id received")
  155. }
  156. self.opts.ConnectionId = ready.Args[0]
  157. log.Debugf("connection id %s", self.opts.ConnectionId)
  158. return nil
  159. }