forked from kaiakz/rsync-os
/
connection.go
129 lines (109 loc) · 2.57 KB
/
connection.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
119
120
121
122
123
124
125
126
127
128
129
package rsync
import (
"bytes"
"encoding/binary"
"io"
)
type SendReceiver interface {
Sync() error
}
// io.ReadWriteCloser
// This struct has two main attributes, both of them can be used for a plain socket or an SSH
type Conn struct {
writer io.WriteCloser // Write only
reader io.ReadCloser // Read only
bytespool []byte // Anti memory-wasted, default size: 8 bytes
}
func (conn *Conn) Write(p []byte) (n int, err error) {
return conn.writer.Write(p)
}
func (conn *Conn) Read(p []byte) (n int, err error) {
return conn.reader.Read(p)
}
/* Encoding: little endian */
// size of: int: 4, long: 8, varint: 4 or 8
func (conn *Conn) ReadByte() (byte, error) {
val := conn.bytespool[:1]
_, err := io.ReadFull(conn, val)
if err != nil {
return 0, err
}
return conn.bytespool[0], nil
}
func (conn *Conn) ReadShort() (int16, error) {
val := conn.bytespool[:2]
_, err := io.ReadFull(conn, val)
if err != nil {
return 0, err
}
return int16(binary.LittleEndian.Uint16(val)), nil
}
func (conn *Conn) ReadInt() (int32, error) {
val := conn.bytespool[:4]
_, err := io.ReadFull(conn, val)
if err != nil {
return 0, err
}
return int32(binary.LittleEndian.Uint32(val)), nil
}
func (conn *Conn) ReadLong() (int64, error) {
val := conn.bytespool[:8]
_, err := io.ReadFull(conn, val)
if err != nil {
return 0, err
}
return int64(binary.LittleEndian.Uint64(val)), nil
}
func (conn *Conn) ReadVarint() (int64, error) {
sval, err := conn.ReadInt()
if err != nil {
return 0, err
}
if sval != -1 {
return int64(sval), nil
}
return conn.ReadLong()
}
func (conn *Conn) WriteByte(data byte) error {
return binary.Write(conn.writer, binary.LittleEndian, data)
}
func (conn *Conn) WriteShort(data int16) error {
return binary.Write(conn.writer, binary.LittleEndian, data)
}
func (conn *Conn) WriteInt(data int32) error {
return binary.Write(conn.writer, binary.LittleEndian, data)
}
func (conn *Conn) WriteLong(data int64) error {
return binary.Write(conn.writer, binary.LittleEndian, data)
}
// TODO: If both writer and reader are based on a same Connection (socket, SSH), how to close them twice?
func (conn *Conn) Close() error {
_ = conn.writer.Close()
_ = conn.reader.Close()
return nil
}
func readLine(conn *Conn) (string, error) {
// until \n, then add \0
line := new(bytes.Buffer)
for {
c, err := conn.ReadByte()
if err != nil {
return "", err
}
if c == '\r' {
continue
}
err = line.WriteByte(c)
if err != nil {
return "", err
}
if c == '\n' {
line.WriteByte(0)
break
}
if c == 0 {
break
}
}
return line.String(), nil
}