|  | // 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; | 
|  |  | 
|  | /// A server socket, providing a stream of high-level [Socket]s. | 
|  | /// | 
|  | /// See [SecureSocket] for more info. | 
|  | class SecureServerSocket extends Stream<SecureSocket> | 
|  | implements ServerSocketBase<SecureSocket> { | 
|  | final RawSecureServerSocket _socket; | 
|  |  | 
|  | SecureServerSocket._(this._socket); | 
|  |  | 
|  | /// Listens on a given address and port. | 
|  | /// | 
|  | /// When the returned 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]. | 
|  | /// | 
|  | /// The [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 negotiation 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 same 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, | 
|  | ); | 
|  | } | 
|  |  | 
|  | /// The port used by this socket. | 
|  | int get port => _socket.port; | 
|  |  | 
|  | /// The address used by this socket. | 
|  | InternetAddress get address => _socket.address; | 
|  |  | 
|  | /// Closes this 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// 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, | 
|  | ); | 
|  | } | 
|  |  | 
|  | /// Listens on a provided address and port. | 
|  | /// | 
|  | /// When the returned 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, | 
|  | ); | 
|  | } | 
|  |  | 
|  | /// The port used by this socket. | 
|  | int get port => _socket.port; | 
|  |  | 
|  | /// The address used by this socket. | 
|  | InternetAddress get address => _socket.address; | 
|  |  | 
|  | /// Closes this 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 _RawSocketBase)._owner = owner; | 
|  | } | 
|  | } |