// 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.

// @dart = 2.5

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;
  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,
            context: _context,
            is_server: true,
            socket: connection,
            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;
  }
}
