OSDN Git Service

versoin1.1.9 (#594)
[bytom/vapor.git] / vendor / golang.org / x / crypto / ssh / buffer.go
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 }