1 | // Copyright 2018 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 jsonrpc2 |
6 | |
7 | import ( |
8 | "context" |
9 | "io" |
10 | "net" |
11 | "os" |
12 | ) |
13 | |
14 | // This file contains implementations of the transport primitives that use the standard network |
15 | // package. |
16 | |
17 | // NetListenOptions is the optional arguments to the NetListen function. |
18 | type NetListenOptions struct { |
19 | NetListenConfig net.ListenConfig |
20 | NetDialer net.Dialer |
21 | } |
22 | |
23 | // NetListener returns a new Listener that listens on a socket using the net package. |
24 | func NetListener(ctx context.Context, network, address string, options NetListenOptions) (Listener, error) { |
25 | ln, err := options.NetListenConfig.Listen(ctx, network, address) |
26 | if err != nil { |
27 | return nil, err |
28 | } |
29 | return &netListener{net: ln}, nil |
30 | } |
31 | |
32 | // netListener is the implementation of Listener for connections made using the net package. |
33 | type netListener struct { |
34 | net net.Listener |
35 | } |
36 | |
37 | // Accept blocks waiting for an incoming connection to the listener. |
38 | func (l *netListener) Accept(context.Context) (io.ReadWriteCloser, error) { |
39 | return l.net.Accept() |
40 | } |
41 | |
42 | // Close will cause the listener to stop listening. It will not close any connections that have |
43 | // already been accepted. |
44 | func (l *netListener) Close() error { |
45 | addr := l.net.Addr() |
46 | err := l.net.Close() |
47 | if addr.Network() == "unix" { |
48 | rerr := os.Remove(addr.String()) |
49 | if rerr != nil && err == nil { |
50 | err = rerr |
51 | } |
52 | } |
53 | return err |
54 | } |
55 | |
56 | // Dialer returns a dialer that can be used to connect to the listener. |
57 | func (l *netListener) Dialer() Dialer { |
58 | return NetDialer(l.net.Addr().Network(), l.net.Addr().String(), net.Dialer{}) |
59 | } |
60 | |
61 | // NetDialer returns a Dialer using the supplied standard network dialer. |
62 | func NetDialer(network, address string, nd net.Dialer) Dialer { |
63 | return &netDialer{ |
64 | network: network, |
65 | address: address, |
66 | dialer: nd, |
67 | } |
68 | } |
69 | |
70 | type netDialer struct { |
71 | network string |
72 | address string |
73 | dialer net.Dialer |
74 | } |
75 | |
76 | func (n *netDialer) Dial(ctx context.Context) (io.ReadWriteCloser, error) { |
77 | return n.dialer.DialContext(ctx, n.network, n.address) |
78 | } |
79 | |
80 | // NetPipeListener returns a new Listener that listens using net.Pipe. |
81 | // It is only possibly to connect to it using the Dialer returned by the |
82 | // Dialer method, each call to that method will generate a new pipe the other |
83 | // side of which will be returned from the Accept call. |
84 | func NetPipeListener(ctx context.Context) (Listener, error) { |
85 | return &netPiper{ |
86 | done: make(chan struct{}), |
87 | dialed: make(chan io.ReadWriteCloser), |
88 | }, nil |
89 | } |
90 | |
91 | // netPiper is the implementation of Listener build on top of net.Pipes. |
92 | type netPiper struct { |
93 | done chan struct{} |
94 | dialed chan io.ReadWriteCloser |
95 | } |
96 | |
97 | // Accept blocks waiting for an incoming connection to the listener. |
98 | func (l *netPiper) Accept(context.Context) (io.ReadWriteCloser, error) { |
99 | // Block until the pipe is dialed or the listener is closed, |
100 | // preferring the latter if already closed at the start of Accept. |
101 | select { |
102 | case <-l.done: |
103 | return nil, errClosed |
104 | default: |
105 | } |
106 | select { |
107 | case rwc := <-l.dialed: |
108 | return rwc, nil |
109 | case <-l.done: |
110 | return nil, errClosed |
111 | } |
112 | } |
113 | |
114 | // Close will cause the listener to stop listening. It will not close any connections that have |
115 | // already been accepted. |
116 | func (l *netPiper) Close() error { |
117 | // unblock any accept calls that are pending |
118 | close(l.done) |
119 | return nil |
120 | } |
121 | |
122 | func (l *netPiper) Dialer() Dialer { |
123 | return l |
124 | } |
125 | |
126 | func (l *netPiper) Dial(ctx context.Context) (io.ReadWriteCloser, error) { |
127 | client, server := net.Pipe() |
128 | |
129 | select { |
130 | case l.dialed <- server: |
131 | return client, nil |
132 | |
133 | case <-l.done: |
134 | client.Close() |
135 | server.Close() |
136 | return nil, errClosed |
137 | } |
138 | } |
139 |
Members