OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 part of dart.io; | |
6 | |
7 /** | |
8 * The [SecureServerSocket] is a server socket, providing a stream of high-level | |
9 * [Socket]s. | |
10 * | |
11 * See [SecureSocket] for more info. | |
12 */ | |
13 class SecureServerSocket extends Stream<SecureSocket> { | |
14 final RawSecureServerSocket _socket; | |
15 | |
16 SecureServerSocket._(this._socket); | |
17 | |
18 /** | |
19 * Returns a future for a [SecureServerSocket]. When the future | |
20 * completes the server socket is bound to the given [address] and | |
21 * [port] and has started listening on it. | |
22 * | |
23 * The [address] can either be a [String] or an | |
24 * [InternetAddress]. If [address] is a [String], [bind] will | |
25 * perform a [InternetAddress.lookup] and use the first value in the | |
26 * list. To listen on the loopback adapter, which will allow only | |
27 * incoming connections from the local host, use the value | |
28 * [InternetAddress.LOOPBACK_IP_V4] or | |
29 * [InternetAddress.LOOPBACK_IP_V6]. To allow for incoming | |
30 * connection from the network use either one of the values | |
31 * [InternetAddress.ANY_IP_V4] or [InternetAddress.ANY_IP_V6] to | |
32 * bind to all interfaces or the IP address of a specific interface. | |
33 * | |
34 * If [port] has the value [:0:] an ephemeral port will be chosen by | |
35 * the system. The actual port used can be retrieved using the | |
36 * [port] getter. | |
37 * | |
38 * The optional argument [backlog] can be used to specify the listen | |
39 * backlog for the underlying OS listen setup. If [backlog] has the | |
40 * value of [:0:] (the default) a reasonable value will be chosen by | |
41 * the system. | |
42 * | |
43 * Incoming client connections are promoted to secure connections, using | |
44 * the server certificate and key set in [context]. | |
45 * | |
46 * [address] must be given as a numeric address, not a host name. | |
47 * | |
48 * To request or require that clients authenticate by providing an SSL (TLS) | |
49 * client certificate, set the optional parameter [requestClientCertificate] | |
50 * or [requireClientCertificate] to true. Requiring a certificate implies | |
51 * requesting a certificate, so setting both is redundant. | |
52 * To check whether a client certificate was received, check | |
53 * SecureSocket.peerCertificate after connecting. If no certificate | |
54 * was received, the result will be null. | |
55 * | |
56 * The optional argument [shared] specifies whether additional | |
57 * SecureServerSocket objects can bind to the same combination of `address`, | |
58 * `port` and `v6Only`. If `shared` is `true` and more `SecureServerSocket`s | |
59 * from this isolate or other isolates are bound to the port, then the | |
60 * incoming connections will be distributed among all the bound | |
61 * `SecureServerSocket`s. Connections can be distributed over multiple | |
62 * isolates this way. | |
63 */ | |
64 static Future<SecureServerSocket> bind( | |
65 address, | |
66 int port, | |
67 SecurityContext context, | |
68 {int backlog: 0, | |
69 bool v6Only: false, | |
70 bool requestClientCertificate: false, | |
71 bool requireClientCertificate: false, | |
72 List<String> supportedProtocols, | |
73 bool shared: false}) { | |
74 return RawSecureServerSocket.bind( | |
75 address, | |
76 port, | |
77 context, | |
78 backlog: backlog, | |
79 v6Only: v6Only, | |
80 requestClientCertificate: requestClientCertificate, | |
81 requireClientCertificate: requireClientCertificate, | |
82 supportedProtocols: supportedProtocols, | |
83 shared: shared).then( | |
84 (serverSocket) => new SecureServerSocket._(serverSocket)); | |
85 } | |
86 | |
87 StreamSubscription<SecureSocket> listen(void onData(SecureSocket socket), | |
88 {Function onError, | |
89 void onDone(), | |
90 bool cancelOnError}) { | |
91 return _socket.map((rawSocket) => new SecureSocket._(rawSocket)) | |
92 .listen(onData, | |
93 onError: onError, | |
94 onDone: onDone, | |
95 cancelOnError: cancelOnError); | |
96 } | |
97 | |
98 /** | |
99 * Returns the port used by this socket. | |
100 */ | |
101 int get port => _socket.port; | |
102 | |
103 /** | |
104 * Returns the address used by this socket. | |
105 */ | |
106 InternetAddress get address => _socket.address; | |
107 | |
108 /** | |
109 * Closes the socket. The returned future completes when the socket | |
110 * is fully closed and is no longer bound. | |
111 */ | |
112 Future<SecureServerSocket> close() => _socket.close().then((_) => this); | |
113 | |
114 void set _owner(owner) { _socket._owner = owner; } | |
115 } | |
116 | |
117 | |
118 /** | |
119 * The RawSecureServerSocket is a server socket, providing a stream of low-level | |
120 * [RawSecureSocket]s. | |
121 * | |
122 * See [RawSecureSocket] for more info. | |
123 */ | |
124 class RawSecureServerSocket extends Stream<RawSecureSocket> { | |
125 final RawServerSocket _socket; | |
126 StreamController<RawSecureSocket> _controller; | |
127 StreamSubscription<RawSocket> _subscription; | |
128 final SecurityContext _context; | |
129 final bool requestClientCertificate; | |
130 final bool requireClientCertificate; | |
131 final List<String> supportedProtocols; | |
132 bool _closed = false; | |
133 | |
134 RawSecureServerSocket._(this._socket, | |
135 this._context, | |
136 this.requestClientCertificate, | |
137 this.requireClientCertificate, | |
138 this.supportedProtocols) { | |
139 _controller = new StreamController<RawSecureSocket>( | |
140 sync: true, | |
141 onListen: _onSubscriptionStateChange, | |
142 onPause: _onPauseStateChange, | |
143 onResume: _onPauseStateChange, | |
144 onCancel: _onSubscriptionStateChange); | |
145 } | |
146 | |
147 /** | |
148 * Returns a future for a [RawSecureServerSocket]. When the future | |
149 * completes the server socket is bound to the given [address] and | |
150 * [port] and has started listening on it. | |
151 * | |
152 * The [address] can either be a [String] or an | |
153 * [InternetAddress]. If [address] is a [String], [bind] will | |
154 * perform a [InternetAddress.lookup] and use the first value in the | |
155 * list. To listen on the loopback adapter, which will allow only | |
156 * incoming connections from the local host, use the value | |
157 * [InternetAddress.LOOPBACK_IP_V4] or | |
158 * [InternetAddress.LOOPBACK_IP_V6]. To allow for incoming | |
159 * connection from the network use either one of the values | |
160 * [InternetAddress.ANY_IP_V4] or [InternetAddress.ANY_IP_V6] to | |
161 * bind to all interfaces or the IP address of a specific interface. | |
162 * | |
163 * If [port] has the value [:0:] an ephemeral port will be chosen by | |
164 * the system. The actual port used can be retrieved using the | |
165 * [port] getter. | |
166 * | |
167 * The optional argument [backlog] can be used to specify the listen | |
168 * backlog for the underlying OS listen setup. If [backlog] has the | |
169 * value of [:0:] (the default) a reasonable value will be chosen by | |
170 * the system. | |
171 * | |
172 * Incoming client connections are promoted to secure connections, | |
173 * using the server certificate and key set in [context]. | |
174 * | |
175 * [address] must be given as a numeric address, not a host name. | |
176 * | |
177 * To request or require that clients authenticate by providing an SSL (TLS) | |
178 * client certificate, set the optional parameters requestClientCertificate or | |
179 * requireClientCertificate to true. Require implies request, so one doesn't | |
180 * need to specify both. To check whether a client certificate was received, | |
181 * check SecureSocket.peerCertificate after connecting. If no certificate | |
182 * was received, the result will be null. | |
183 * | |
184 * The optional argument [shared] specifies whether additional | |
185 * RawSecureServerSocket objects can bind to the same combination of | |
186 * `address`, `port` and `v6Only`. If `shared` is `true` and more | |
187 * `RawSecureServerSocket`s from this isolate or other isolates are bound to | |
188 * the port, then the incoming connections will be distributed among all the | |
189 * bound `RawSecureServerSocket`s. Connections can be distributed over | |
190 * multiple isolates this way. | |
191 */ | |
192 static Future<RawSecureServerSocket> bind( | |
193 address, | |
194 int port, | |
195 SecurityContext context, | |
196 {int backlog: 0, | |
197 bool v6Only: false, | |
198 bool requestClientCertificate: false, | |
199 bool requireClientCertificate: false, | |
200 List<String> supportedProtocols, | |
201 bool shared: false}) { | |
202 return RawServerSocket.bind( | |
203 address, port, backlog: backlog, v6Only: v6Only, shared: shared) | |
204 .then((serverSocket) => new RawSecureServerSocket._( | |
205 serverSocket, | |
206 context, | |
207 requestClientCertificate, | |
208 requireClientCertificate, | |
209 supportedProtocols)); | |
210 } | |
211 | |
212 StreamSubscription<RawSecureSocket> listen(void onData(RawSecureSocket s), | |
213 {Function onError, | |
214 void onDone(), | |
215 bool cancelOnError}) { | |
216 return _controller.stream.listen(onData, | |
217 onError: onError, | |
218 onDone: onDone, | |
219 cancelOnError: cancelOnError); | |
220 } | |
221 | |
222 /** | |
223 * Returns the port used by this socket. | |
224 */ | |
225 int get port => _socket.port; | |
226 | |
227 /** | |
228 * Returns the address used by this socket. | |
229 */ | |
230 InternetAddress get address => _socket.address; | |
231 | |
232 /** | |
233 * Closes the socket. The returned future completes when the socket | |
234 * is fully closed and is no longer bound. | |
235 */ | |
236 Future<RawSecureServerSocket> close() { | |
237 _closed = true; | |
238 return _socket.close().then((_) => this); | |
239 } | |
240 | |
241 void _onData(RawSocket connection) { | |
242 var remotePort; | |
243 try { | |
244 remotePort = connection.remotePort; | |
245 } catch (e) { | |
246 // If connection is already closed, remotePort throws an exception. | |
247 // Do nothing - connection is closed. | |
248 return; | |
249 } | |
250 _RawSecureSocket.connect( | |
251 connection.address, | |
252 remotePort, | |
253 context: _context, | |
254 is_server: true, | |
255 socket: connection, | |
256 requestClientCertificate: requestClientCertificate, | |
257 requireClientCertificate: requireClientCertificate, | |
258 supportedProtocols: supportedProtocols) | |
259 .then((RawSecureSocket secureConnection) { | |
260 if (_closed) { | |
261 secureConnection.close(); | |
262 } else { | |
263 _controller.add(secureConnection); | |
264 } | |
265 }).catchError((e, s) { | |
266 if (!_closed) { | |
267 _controller.addError(e, s); | |
268 } | |
269 }); | |
270 } | |
271 | |
272 void _onPauseStateChange() { | |
273 if (_controller.isPaused) { | |
274 _subscription.pause(); | |
275 } else { | |
276 _subscription.resume(); | |
277 } | |
278 } | |
279 | |
280 void _onSubscriptionStateChange() { | |
281 if (_controller.hasListener) { | |
282 _subscription = _socket.listen(_onData, | |
283 onError: _controller.addError, | |
284 onDone: _controller.close); | |
285 } else { | |
286 close(); | |
287 } | |
288 } | |
289 | |
290 void set _owner(owner) { | |
291 (_socket as dynamic)._owner = owner; | |
292 } | |
293 } | |
294 | |
295 | |
OLD | NEW |