diff options
Diffstat (limited to 'vendor/golang.org/x/crypto/ssh/buffer.go')
-rw-r--r-- | vendor/golang.org/x/crypto/ssh/buffer.go | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/vendor/golang.org/x/crypto/ssh/buffer.go b/vendor/golang.org/x/crypto/ssh/buffer.go new file mode 100644 index 0000000..6931b51 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/buffer.go | |||
@@ -0,0 +1,98 @@ | |||
1 | // Copyright 2012 The Go Authors. All rights reserved. | ||
2 | // Use of this source code is governed by a BSD-style | ||
3 | // license that can be found in the LICENSE file. | ||
4 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "io" | ||
9 | "sync" | ||
10 | ) | ||
11 | |||
12 | // buffer provides a linked list buffer for data exchange | ||
13 | // between producer and consumer. Theoretically the buffer is | ||
14 | // of unlimited capacity as it does no allocation of its own. | ||
15 | type buffer struct { | ||
16 | // protects concurrent access to head, tail and closed | ||
17 | *sync.Cond | ||
18 | |||
19 | head *element // the buffer that will be read first | ||
20 | tail *element // the buffer that will be read last | ||
21 | |||
22 | closed bool | ||
23 | } | ||
24 | |||
25 | // An element represents a single link in a linked list. | ||
26 | type element struct { | ||
27 | buf []byte | ||
28 | next *element | ||
29 | } | ||
30 | |||
31 | // newBuffer returns an empty buffer that is not closed. | ||
32 | func newBuffer() *buffer { | ||
33 | e := new(element) | ||
34 | b := &buffer{ | ||
35 | Cond: newCond(), | ||
36 | head: e, | ||
37 | tail: e, | ||
38 | } | ||
39 | return b | ||
40 | } | ||
41 | |||
42 | // write makes buf available for Read to receive. | ||
43 | // buf must not be modified after the call to write. | ||
44 | func (b *buffer) write(buf []byte) { | ||
45 | b.Cond.L.Lock() | ||
46 | e := &element{buf: buf} | ||
47 | b.tail.next = e | ||
48 | b.tail = e | ||
49 | b.Cond.Signal() | ||
50 | b.Cond.L.Unlock() | ||
51 | } | ||
52 | |||
53 | // eof closes the buffer. Reads from the buffer once all | ||
54 | // the data has been consumed will receive os.EOF. | ||
55 | func (b *buffer) eof() error { | ||
56 | b.Cond.L.Lock() | ||
57 | b.closed = true | ||
58 | b.Cond.Signal() | ||
59 | b.Cond.L.Unlock() | ||
60 | return nil | ||
61 | } | ||
62 | |||
63 | // Read reads data from the internal buffer in buf. Reads will block | ||
64 | // if no data is available, or until the buffer is closed. | ||
65 | func (b *buffer) Read(buf []byte) (n int, err error) { | ||
66 | b.Cond.L.Lock() | ||
67 | defer b.Cond.L.Unlock() | ||
68 | |||
69 | for len(buf) > 0 { | ||
70 | // if there is data in b.head, copy it | ||
71 | if len(b.head.buf) > 0 { | ||
72 | r := copy(buf, b.head.buf) | ||
73 | buf, b.head.buf = buf[r:], b.head.buf[r:] | ||
74 | n += r | ||
75 | continue | ||
76 | } | ||
77 | // if there is a next buffer, make it the head | ||
78 | if len(b.head.buf) == 0 && b.head != b.tail { | ||
79 | b.head = b.head.next | ||
80 | continue | ||
81 | } | ||
82 | |||
83 | // if at least one byte has been copied, return | ||
84 | if n > 0 { | ||
85 | break | ||
86 | } | ||
87 | |||
88 | // if nothing was read, and there is nothing outstanding | ||
89 | // check to see if the buffer is closed. | ||
90 | if b.closed { | ||
91 | err = io.EOF | ||
92 | break | ||
93 | } | ||
94 | // out of buffers, wait for producer | ||
95 | b.Cond.Wait() | ||
96 | } | ||
97 | return | ||
98 | } | ||