-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathconn.go
More file actions
258 lines (208 loc) · 7.44 KB
/
Copy pathconn.go
File metadata and controls
258 lines (208 loc) · 7.44 KB
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/*
* Copyright 2024 the urpc project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package uio
import (
"fmt"
"io"
"net"
"sync"
"sync/atomic"
"time"
"github.com/urpc/uio/internal/bytebuf"
)
// Conn is an interface of underlying connection.
type Conn interface {
// LocalAddr is the connection's local socket address.
LocalAddr() net.Addr
// RemoteAddr is the connection's remote address.
RemoteAddr() net.Addr
// Context returns a user-defined context, it's not concurrency-safe.
Context() interface{}
// SetContext sets a user-defined context, it's not concurrency-safe.
SetContext(ctx interface{})
// SetLinger sets the behavior of Close on a connection which still
// has data waiting to be sent or to be acknowledged.
//
// If sec < 0 (the default), the operating system finishes sending the
// data in the background.
//
// If sec == 0, the operating system discards any unsent or
// unacknowledged data.
//
// If sec > 0, the data is sent in the background as with sec < 0. On
// some operating systems after sec seconds have elapsed any remaining
// unsent data may be discarded.
SetLinger(secs int) error
// SetNoDelay controls whether the operating system should delay
// packet transmission in hopes of sending fewer packets (Nagle's
// algorithm).
// The default is true (no delay), meaning that data is sent as soon as possible after a Write.
SetNoDelay(nodelay bool) error
// SetKeepAlive sets whether the operating system should send
// keep-alive messages on the connection.
SetKeepAlive(keepalive bool) error
// SetKeepAlivePeriod tells operating system to send keep-alive messages on the connection
// and sets period between TCP keep-alive probes.
SetKeepAlivePeriod(secs int) error
// SetReadBuffer sets the size of the operating system's
// receive buffer associated with the connection.
SetReadBuffer(size int) error
// SetWriteBuffer sets the size of the operating system's
// transmit buffer associated with the connection.
SetWriteBuffer(size int) error
// SetDeadline sets deadline for both read and write.
// If it is time.Zero, SetDeadline will clear the deadlines.
SetDeadline(t time.Time) error
// SetReadDeadline sets the deadline for future Read calls.
// When the user doesn't update the deadline and the deadline exceeds,
// the connection will be closed.
// If it is time.Zero, SetReadDeadline will clear the deadline.
SetReadDeadline(t time.Time) error
// SetWriteDeadline sets the deadline for future data writing.
// If it is time.Zero, SetReadDeadline will clear the deadline.
SetWriteDeadline(t time.Time) error
// Peek returns the next len(b) bytes without advancing the inbound buffer.
// it's not concurrency-safe.
Peek(b []byte) []byte
// Discard advances the inbound buffer with next n bytes, returning the number of bytes discarded.
// it's not concurrency-safe.
Discard(n int) (int, error)
// InboundBuffered returns a inbound buffer data length.
// it's not concurrency-safe.
InboundBuffered() int
// OutboundBuffered returns a outbound buffer data length.
OutboundBuffered() int
// WriterTo
// it's not concurrency-safe.
// Notice: non-blocking interface, should not be used as you use std.
io.WriterTo
// ReadWriteCloser
// Read() it's not concurrency-safe.
// Notice: non-blocking interface, should not be used as you use std.
io.ReadWriteCloser
// ByteWriter
// Notice: non-blocking interface, should not be used as you use std.
io.ByteWriter
// StringWriter
// Notice: non-blocking interface, should not be used as you use std.
io.StringWriter
// Writev "writev"-like batch write optimization.
// Notice: non-blocking interface, should not be used as you use std.
Writev(vec [][]byte) (int, error)
// Flush writes any buffered data to the underlying connection.
// Notice: non-blocking interface, should not be used as you use std.
Flush() error
// CloseWith close the connection with error.
CloseWith(err error) error
}
var errUnsupported = fmt.Errorf("unsupported method")
type commonConn struct {
events *Events // events
loop *eventLoop // event loop
localAddr net.Addr // local address
remoteAddr net.Addr // remote address
closed int32 // closed flag
err error // close error
ctx interface{} // user-defined data
mux sync.Mutex // outbound buffer & udpConns
outbound bytebuf.CompositeBuffer // outbound buffer
inbound bytebuf.CompositeBuffer // inbound buffer
inboundTail []byte // inbound tail buffer
}
func (fc *commonConn) LocalAddr() net.Addr { return fc.localAddr }
func (fc *commonConn) RemoteAddr() net.Addr { return fc.remoteAddr }
func (fc *commonConn) Context() interface{} { return fc.ctx }
func (fc *commonConn) SetContext(ctx interface{}) { fc.ctx = ctx }
func (fc *commonConn) SetDeadline(t time.Time) error { return errUnsupported }
func (fc *commonConn) SetReadDeadline(t time.Time) error { return errUnsupported }
func (fc *commonConn) SetWriteDeadline(t time.Time) error { return errUnsupported }
func (fc *commonConn) IsClosed() bool {
return 0 != atomic.LoadInt32(&fc.closed)
}
func (fc *commonConn) WriteTo(w io.Writer) (n int64, err error) {
if !fc.inbound.Empty() {
n, err = fc.inbound.WriteTo(w)
}
if nil == err && 0 != len(fc.inboundTail) {
var sz int
sz, err = w.Write(fc.inboundTail)
n += int64(sz)
fc.inboundTail = fc.inboundTail[sz:]
}
return
}
func (fc *commonConn) Read(b []byte) (n int, err error) {
if !fc.inbound.Empty() {
if n, _ = fc.inbound.Read(b); n == len(b) {
return
}
}
if 0 != len(fc.inboundTail) {
sz := copy(b[n:], fc.inboundTail)
n += sz
fc.inboundTail = fc.inboundTail[sz:]
}
return
}
func (fc *commonConn) Peek(b []byte) []byte {
// inbound buffer size
inboundLen := fc.inbound.Len()
inboundTailLen := len(fc.inboundTail)
if 0 == len(b) || 0 == (inboundLen+inboundTailLen) {
return nil
}
if 0 == inboundLen {
n := min(len(b), len(fc.inboundTail))
return fc.inboundTail[:n]
}
data := fc.inbound.Peek(b)
if n := len(data); n < len(b) {
n += copy(b[n:], fc.inboundTail)
return b[:n]
}
return data
}
func (fc *commonConn) Discard(n int) (int, error) {
// inbound buffer size
inboundLen := fc.inbound.Len()
inboundTailLen := len(fc.inboundTail)
// discard all inbound buffer
if n < 0 || n > (inboundLen+inboundTailLen) {
n = inboundLen + inboundTailLen
}
if 0 == n {
return 0, nil
}
if 0 == inboundLen {
fc.inboundTail = fc.inboundTail[n:]
return n, nil
}
if n <= inboundLen {
fc.inbound.Discard(n)
return n, nil
}
fc.inbound.Discard(inboundLen)
fc.inboundTail = fc.inboundTail[n-inboundLen:]
return n, nil
}
func (fc *commonConn) InboundBuffered() int {
return fc.inbound.Len() + len(fc.inboundTail)
}
func (fc *commonConn) OutboundBuffered() int {
fc.mux.Lock()
defer fc.mux.Unlock()
return fc.outbound.Len()
}