-
Notifications
You must be signed in to change notification settings - Fork 36
/
memconn_listener.go
105 lines (94 loc) · 2.29 KB
/
memconn_listener.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
package memconn
import (
"context"
"errors"
"net"
"sync"
)
// Listener implements the net.Listener interface.
type Listener struct {
addr Addr
once sync.Once
rcvr chan *Conn
done chan struct{}
rmvd chan struct{}
}
func (l *Listener) dial(
ctx context.Context,
network string,
laddr, raddr Addr) (*Conn, error) {
local, remote := makeNewConns(network, laddr, raddr)
// TODO Figure out if this logic is valid.
//
// Start a goroutine that closes the remote side of the connection
// as soon as the listener's done channel is no longer blocked.
//go func() {
// <-l.done
// remoteConn.Close()
//}()
// If the provided context is nill then announce a new connection
// by placing the new remoteConn onto the rcvr channel. An Accept
// call from this listener will remove the remoteConn from the channel.
if ctx == nil {
l.rcvr <- remote
return local, nil
}
// Announce a new connection by placing the new remoteConn
// onto the rcvr channel. An Accept call from this listener will
// remove the remoteConn from the channel. However, if that does
// not occur by the time the context times out / is cancelled, then
// an error is returned.
select {
case l.rcvr <- remote:
return local, nil
case <-ctx.Done():
local.Close()
remote.Close()
return nil, &net.OpError{
Addr: raddr,
Source: laddr,
Net: network,
Op: "dial",
Err: ctx.Err(),
}
}
}
// Accept implements the net.Listener Accept method.
func (l *Listener) Accept() (net.Conn, error) {
return l.AcceptMemConn()
}
// AcceptMemConn implements the net.Listener Accept method logic and
// returns a *memconn.Conn object.
func (l *Listener) AcceptMemConn() (*Conn, error) {
select {
case remoteConn, ok := <-l.rcvr:
if ok {
return remoteConn, nil
}
return nil, &net.OpError{
Addr: l.addr,
Source: l.addr,
Net: l.addr.Network(),
Err: errors.New("listener closed"),
}
case <-l.done:
return nil, &net.OpError{
Addr: l.addr,
Source: l.addr,
Net: l.addr.Network(),
Err: errors.New("listener closed"),
}
}
}
// Close implements the net.Listener Close method.
func (l *Listener) Close() error {
l.once.Do(func() {
close(l.done)
<-l.rmvd
})
return nil
}
// Addr implements the net.Listener Addr method.
func (l *Listener) Addr() net.Addr {
return l.addr
}