|  | // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | part of dart.io; | 
|  |  | 
|  | /** | 
|  | * The [SecureServerSocket] is a server socket, providing a stream of high-level | 
|  | * [Socket]s. | 
|  | * | 
|  | * See [SecureSocket] for more info. | 
|  | */ | 
|  | class SecureServerSocket extends Stream<SecureSocket> { | 
|  | final RawSecureServerSocket _socket; | 
|  |  | 
|  | SecureServerSocket._(this._socket); | 
|  |  | 
|  | /** | 
|  | * Returns a future for a [SecureServerSocket]. When the future | 
|  | * completes the server socket is bound to the given [address] and | 
|  | * [port] and has started listening on it. | 
|  | * | 
|  | * The [address] can either be a [String] or an | 
|  | * [InternetAddress]. If [address] is a [String], [bind] will | 
|  | * perform a [InternetAddress.lookup] and use the first value in the | 
|  | * list. To listen on the loopback adapter, which will allow only | 
|  | * incoming connections from the local host, use the value | 
|  | * [InternetAddress.loopbackIPv4] or | 
|  | * [InternetAddress.loopbackIPv6]. To allow for incoming | 
|  | * connection from the network use either one of the values | 
|  | * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to | 
|  | * bind to all interfaces or the IP address of a specific interface. | 
|  | * | 
|  | * If [port] has the value [:0:] an ephemeral port will be chosen by | 
|  | * the system. The actual port used can be retrieved using the | 
|  | * [port] getter. | 
|  | * | 
|  | * The optional argument [backlog] can be used to specify the listen | 
|  | * backlog for the underlying OS listen setup. If [backlog] has the | 
|  | * value of [:0:] (the default) a reasonable value will be chosen by | 
|  | * the system. | 
|  | * | 
|  | * Incoming client connections are promoted to secure connections, using | 
|  | * the server certificate and key set in [context]. | 
|  | * | 
|  | * [address] must be given as a numeric address, not a host name. | 
|  | * | 
|  | * To request or require that clients authenticate by providing an SSL (TLS) | 
|  | * client certificate, set the optional parameter [requestClientCertificate] | 
|  | * or [requireClientCertificate] to true.  Requiring a certificate implies | 
|  | * requesting a certificate, so setting both is redundant. | 
|  | * To check whether a client certificate was received, check | 
|  | * SecureSocket.peerCertificate after connecting.  If no certificate | 
|  | * was received, the result will be null. | 
|  | * | 
|  | * [supportedProtocols] is an optional list of protocols (in decreasing | 
|  | * order of preference) to use during the ALPN protocol negogiation with | 
|  | * clients.  Example values are "http/1.1" or "h2".  The selected protocol | 
|  | * can be obtained via [SecureSocket.selectedProtocol]. | 
|  | * | 
|  | * The optional argument [shared] specifies whether additional | 
|  | * SecureServerSocket objects can bind to the same combination of `address`, | 
|  | * `port` and `v6Only`.  If `shared` is `true` and more `SecureServerSocket`s | 
|  | * from this isolate or other isolates are bound to the port, then the | 
|  | * incoming connections will be distributed among all the bound | 
|  | * `SecureServerSocket`s. Connections can be distributed over multiple | 
|  | * isolates this way. | 
|  | */ | 
|  | static Future<SecureServerSocket> bind( | 
|  | address, int port, SecurityContext? context, | 
|  | {int backlog: 0, | 
|  | bool v6Only: false, | 
|  | bool requestClientCertificate: false, | 
|  | bool requireClientCertificate: false, | 
|  | List<String>? supportedProtocols, | 
|  | bool shared: false}) { | 
|  | return RawSecureServerSocket.bind(address, port, context, | 
|  | backlog: backlog, | 
|  | v6Only: v6Only, | 
|  | requestClientCertificate: requestClientCertificate, | 
|  | requireClientCertificate: requireClientCertificate, | 
|  | supportedProtocols: supportedProtocols, | 
|  | shared: shared) | 
|  | .then((serverSocket) => new SecureServerSocket._(serverSocket)); | 
|  | } | 
|  |  | 
|  | StreamSubscription<SecureSocket> listen(void onData(SecureSocket socket)?, | 
|  | {Function? onError, void onDone()?, bool? cancelOnError}) { | 
|  | return _socket.map((rawSocket) => new SecureSocket._(rawSocket)).listen( | 
|  | onData, | 
|  | onError: onError, | 
|  | onDone: onDone, | 
|  | cancelOnError: cancelOnError); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the port used by this socket. | 
|  | */ | 
|  | int get port => _socket.port; | 
|  |  | 
|  | /** | 
|  | * Returns the address used by this socket. | 
|  | */ | 
|  | InternetAddress get address => _socket.address; | 
|  |  | 
|  | /** | 
|  | * Closes the socket. The returned future completes when the socket | 
|  | * is fully closed and is no longer bound. | 
|  | */ | 
|  | Future<SecureServerSocket> close() => _socket.close().then((_) => this); | 
|  |  | 
|  | void set _owner(owner) { | 
|  | _socket._owner = owner; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * The RawSecureServerSocket is a server socket, providing a stream of low-level | 
|  | * [RawSecureSocket]s. | 
|  | * | 
|  | * See [RawSecureSocket] for more info. | 
|  | */ | 
|  | class RawSecureServerSocket extends Stream<RawSecureSocket> { | 
|  | final RawServerSocket _socket; | 
|  | late StreamController<RawSecureSocket> _controller; | 
|  | StreamSubscription<RawSocket>? _subscription; | 
|  | final SecurityContext? _context; | 
|  | final bool requestClientCertificate; | 
|  | final bool requireClientCertificate; | 
|  | final List<String>? supportedProtocols; | 
|  | bool _closed = false; | 
|  |  | 
|  | RawSecureServerSocket._( | 
|  | this._socket, | 
|  | this._context, | 
|  | this.requestClientCertificate, | 
|  | this.requireClientCertificate, | 
|  | this.supportedProtocols) { | 
|  | _controller = new StreamController<RawSecureSocket>( | 
|  | sync: true, | 
|  | onListen: _onSubscriptionStateChange, | 
|  | onPause: _onPauseStateChange, | 
|  | onResume: _onPauseStateChange, | 
|  | onCancel: _onSubscriptionStateChange); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a future for a [RawSecureServerSocket]. When the future | 
|  | * completes the server socket is bound to the given [address] and | 
|  | * [port] and has started listening on it. | 
|  | * | 
|  | * The [address] can either be a [String] or an | 
|  | * [InternetAddress]. If [address] is a [String], [bind] will | 
|  | * perform a [InternetAddress.lookup] and use the first value in the | 
|  | * list. To listen on the loopback adapter, which will allow only | 
|  | * incoming connections from the local host, use the value | 
|  | * [InternetAddress.loopbackIPv4] or | 
|  | * [InternetAddress.loopbackIPv6]. To allow for incoming | 
|  | * connection from the network use either one of the values | 
|  | * [InternetAddress.anyIPv4] or [InternetAddress.anyIPv6] to | 
|  | * bind to all interfaces or the IP address of a specific interface. | 
|  | * | 
|  | * If [port] has the value [:0:] an ephemeral port will be chosen by | 
|  | * the system. The actual port used can be retrieved using the | 
|  | * [port] getter. | 
|  | * | 
|  | * The optional argument [backlog] can be used to specify the listen | 
|  | * backlog for the underlying OS listen setup. If [backlog] has the | 
|  | * value of [:0:] (the default) a reasonable value will be chosen by | 
|  | * the system. | 
|  | * | 
|  | * Incoming client connections are promoted to secure connections, | 
|  | * using the server certificate and key set in [context]. | 
|  | * | 
|  | * [address] must be given as a numeric address, not a host name. | 
|  | * | 
|  | * To request or require that clients authenticate by providing an SSL (TLS) | 
|  | * client certificate, set the optional parameters requestClientCertificate or | 
|  | * requireClientCertificate to true.  Require implies request, so one doesn't | 
|  | * need to specify both.  To check whether a client certificate was received, | 
|  | * check SecureSocket.peerCertificate after connecting.  If no certificate | 
|  | * was received, the result will be null. | 
|  | * | 
|  | * [supportedProtocols] is an optional list of protocols (in decreasing | 
|  | * order of preference) to use during the ALPN protocol negotiation with | 
|  | * clients.  Example values are "http/1.1" or "h2".  The selected protocol | 
|  | * can be obtained via [RawSecureSocket.selectedProtocol]. | 
|  | * | 
|  | * The optional argument [shared] specifies whether additional | 
|  | * RawSecureServerSocket objects can bind to the same combination of | 
|  | * `address`, `port` and `v6Only`.  If `shared` is `true` and more | 
|  | * `RawSecureServerSocket`s from this isolate or other isolates are bound to | 
|  | * the port, then the incoming connections will be distributed among all the | 
|  | * bound `RawSecureServerSocket`s. Connections can be distributed over | 
|  | * multiple isolates this way. | 
|  | */ | 
|  | static Future<RawSecureServerSocket> bind( | 
|  | address, int port, SecurityContext? context, | 
|  | {int backlog: 0, | 
|  | bool v6Only: false, | 
|  | bool requestClientCertificate: false, | 
|  | bool requireClientCertificate: false, | 
|  | List<String>? supportedProtocols, | 
|  | bool shared: false}) { | 
|  | return RawServerSocket.bind(address, port, | 
|  | backlog: backlog, v6Only: v6Only, shared: shared) | 
|  | .then((serverSocket) => new RawSecureServerSocket._( | 
|  | serverSocket, | 
|  | context, | 
|  | requestClientCertificate, | 
|  | requireClientCertificate, | 
|  | supportedProtocols)); | 
|  | } | 
|  |  | 
|  | StreamSubscription<RawSecureSocket> listen(void onData(RawSecureSocket s)?, | 
|  | {Function? onError, void onDone()?, bool? cancelOnError}) { | 
|  | return _controller.stream.listen(onData, | 
|  | onError: onError, onDone: onDone, cancelOnError: cancelOnError); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the port used by this socket. | 
|  | */ | 
|  | int get port => _socket.port; | 
|  |  | 
|  | /** | 
|  | * Returns the address used by this socket. | 
|  | */ | 
|  | InternetAddress get address => _socket.address; | 
|  |  | 
|  | /** | 
|  | * Closes the socket. The returned future completes when the socket | 
|  | * is fully closed and is no longer bound. | 
|  | */ | 
|  | Future<RawSecureServerSocket> close() { | 
|  | _closed = true; | 
|  | return _socket.close().then((_) => this); | 
|  | } | 
|  |  | 
|  | void _onData(RawSocket connection) { | 
|  | var remotePort; | 
|  | try { | 
|  | remotePort = connection.remotePort; | 
|  | } catch (e) { | 
|  | // If connection is already closed, remotePort throws an exception. | 
|  | // Do nothing - connection is closed. | 
|  | return; | 
|  | } | 
|  | _RawSecureSocket.connect(connection.address, remotePort, true, connection, | 
|  | context: _context, | 
|  | requestClientCertificate: requestClientCertificate, | 
|  | requireClientCertificate: requireClientCertificate, | 
|  | supportedProtocols: supportedProtocols) | 
|  | .then((RawSecureSocket secureConnection) { | 
|  | if (_closed) { | 
|  | secureConnection.close(); | 
|  | } else { | 
|  | _controller.add(secureConnection); | 
|  | } | 
|  | }).catchError((e, s) { | 
|  | if (!_closed) { | 
|  | _controller.addError(e, s); | 
|  | } | 
|  | }); | 
|  | } | 
|  |  | 
|  | void _onPauseStateChange() { | 
|  | if (_controller.isPaused) { | 
|  | _subscription!.pause(); | 
|  | } else { | 
|  | _subscription!.resume(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void _onSubscriptionStateChange() { | 
|  | if (_controller.hasListener) { | 
|  | _subscription = _socket.listen(_onData, | 
|  | onError: _controller.addError, onDone: _controller.close); | 
|  | } else { | 
|  | close(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void set _owner(owner) { | 
|  | (_socket as dynamic)._owner = owner; | 
|  | } | 
|  | } |