blob: 99846ffddb1a3875c147908411381ddefba2192b [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001package sockets
2
3import (
4 "errors"
5 "net"
6 "sync"
7)
8
9var errClosed = errors.New("use of closed network connection")
10
11// InmemSocket implements net.Listener using in-memory only connections.
12type InmemSocket struct {
13 chConn chan net.Conn
14 chClose chan struct{}
15 addr string
16 mu sync.Mutex
17}
18
19// dummyAddr is used to satisfy net.Addr for the in-mem socket
20// it is just stored as a string and returns the string for all calls
21type dummyAddr string
22
23// NewInmemSocket creates an in-memory only net.Listener
24// The addr argument can be any string, but is used to satisfy the `Addr()` part
25// of the net.Listener interface
26func NewInmemSocket(addr string, bufSize int) *InmemSocket {
27 return &InmemSocket{
28 chConn: make(chan net.Conn, bufSize),
29 chClose: make(chan struct{}),
30 addr: addr,
31 }
32}
33
34// Addr returns the socket's addr string to satisfy net.Listener
35func (s *InmemSocket) Addr() net.Addr {
36 return dummyAddr(s.addr)
37}
38
39// Accept implements the Accept method in the Listener interface; it waits for the next call and returns a generic Conn.
40func (s *InmemSocket) Accept() (net.Conn, error) {
41 select {
42 case conn := <-s.chConn:
43 return conn, nil
44 case <-s.chClose:
45 return nil, errClosed
46 }
47}
48
49// Close closes the listener. It will be unavailable for use once closed.
50func (s *InmemSocket) Close() error {
51 s.mu.Lock()
52 defer s.mu.Unlock()
53 select {
54 case <-s.chClose:
55 default:
56 close(s.chClose)
57 }
58 return nil
59}
60
61// Dial is used to establish a connection with the in-mem server
62func (s *InmemSocket) Dial(network, addr string) (net.Conn, error) {
63 srvConn, clientConn := net.Pipe()
64 select {
65 case s.chConn <- srvConn:
66 case <-s.chClose:
67 return nil, errClosed
68 }
69
70 return clientConn, nil
71}
72
73// Network returns the addr string, satisfies net.Addr
74func (a dummyAddr) Network() string {
75 return string(a)
76}
77
78// String returns the string form
79func (a dummyAddr) String() string {
80 return string(a)
81}