-
Notifications
You must be signed in to change notification settings - Fork 48
/
tunnel.go
118 lines (102 loc) · 3.47 KB
/
tunnel.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
package guac
import (
"fmt"
"github.com/google/uuid"
"io"
)
// The Guacamole protocol instruction Opcode reserved for arbitrary
// internal use by tunnel implementations. The value of this Opcode is
// guaranteed to be the empty string (""). Tunnel implementations may use
// this Opcode for any purpose. It is currently used by the HTTP tunnel to
// mark the end of the HTTP response, and by the WebSocket tunnel to
// transmit the tunnel UUID.
const InternalDataOpcode = ""
var internalOpcodeIns = []byte(fmt.Sprint(len(InternalDataOpcode), ".", InternalDataOpcode))
// InstructionReader provides reading functionality to a Stream
type InstructionReader interface {
// ReadSome returns the next complete guacd message from the stream
ReadSome() ([]byte, error)
// Available returns true if there are bytes buffered in the stream
Available() bool
// Flush resets the internal buffer for reuse
Flush()
}
// Tunnel provides a unique identifier and synchronized access to the InstructionReader and Writer
// associated with a Stream.
type Tunnel interface {
// AcquireReader returns a reader to the tunnel if it isn't locked
AcquireReader() InstructionReader
// ReleaseReader releases the lock on the reader
ReleaseReader()
// HasQueuedReaderThreads returns true if there is a reader locked
HasQueuedReaderThreads() bool
// AcquireWriter returns a writer to the tunnel if it isn't locked
AcquireWriter() io.Writer
// ReleaseWriter releases the lock on the writer
ReleaseWriter()
// HasQueuedWriterThreads returns true if there is a writer locked
HasQueuedWriterThreads() bool
// GetUUID returns the uuid of the tunnel
GetUUID() string
// ConnectionId returns the guacd Connection ID of the tunnel
ConnectionID() string
// Close closes the tunnel
Close() error
}
// Base Tunnel implementation which synchronizes access to the underlying reader and writer with locks
type SimpleTunnel struct {
stream *Stream
/**
* The UUID associated with this tunnel. Every tunnel must have a
* corresponding UUID such that tunnel read/write requests can be
* directed to the proper tunnel.
*/
uuid uuid.UUID
readerLock CountedLock
writerLock CountedLock
}
// NewSimpleTunnel creates a new tunnel
func NewSimpleTunnel(stream *Stream) *SimpleTunnel {
return &SimpleTunnel{
stream: stream,
uuid: uuid.New(),
}
}
// AcquireReader acquires the reader lock
func (t *SimpleTunnel) AcquireReader() InstructionReader {
t.readerLock.Lock()
return t.stream
}
// ReleaseReader releases the reader
func (t *SimpleTunnel) ReleaseReader() {
t.readerLock.Unlock()
}
// HasQueuedReaderThreads returns true if more than one goroutine is trying to read
func (t *SimpleTunnel) HasQueuedReaderThreads() bool {
return t.readerLock.HasQueued()
}
// AcquireWriter locks the writer lock
func (t *SimpleTunnel) AcquireWriter() io.Writer {
t.writerLock.Lock()
return t.stream
}
// ReleaseWriter releases the writer lock
func (t *SimpleTunnel) ReleaseWriter() {
t.writerLock.Unlock()
}
// ConnectionID returns the underlying Guacamole connection ID
func (t *SimpleTunnel) ConnectionID() string {
return t.stream.ConnectionID
}
// HasQueuedWriterThreads returns true if more than one goroutine is trying to write
func (t *SimpleTunnel) HasQueuedWriterThreads() bool {
return t.writerLock.HasQueued()
}
// Close closes the underlying stream
func (t *SimpleTunnel) Close() (err error) {
return t.stream.Close()
}
// GetUUID returns the tunnel's UUID
func (t *SimpleTunnel) GetUUID() string {
return t.uuid.String()
}