// Copyright (c) 2013, 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.
//

import "dart:async";
import "dart:io";

import 'test_utils.dart' show retry, throws, withTempDir;

Future testArguments(connectFunction, String socketDir) async {
  var sourceAddress;
  final serverIPv4 = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0);
  serverIPv4.listen((_) {
    throw 'Unexpected connection from address $sourceAddress';
  });

  final serverIPv6 = await ServerSocket.bind(InternetAddress.loopbackIPv6, 0);
  serverIPv6.listen((_) {
    throw 'Unexpected connection from address $sourceAddress';
  });

  ServerSocket serverUnix = await ServerSocket.bind(
      InternetAddress('$socketDir/sock', type: InternetAddressType.unix), 0);
  serverUnix.listen((_) {
    throw 'Unexpected connection from address $sourceAddress';
  });

  // Illegal type for sourceAddress.
  for (sourceAddress in ['www.google.com', 'abc']) {
    await throws(
        () => connectFunction('127.0.0.1', serverIPv4.port,
            sourceAddress: sourceAddress),
        (e) => e is ArgumentError);
  }
  // Unsupported local address.
  for (sourceAddress in ['8.8.8.8', new InternetAddress('8.8.8.8')]) {
    await throws(
        () => connectFunction('127.0.0.1', serverIPv4.port,
            sourceAddress: sourceAddress),
        (e) =>
            e is SocketException &&
            e.address == new InternetAddress('8.8.8.8'));
  }
  // Address family mismatch for IPv4.
  for (sourceAddress in [
    '::1',
    InternetAddress.loopbackIPv6,
    InternetAddress('$socketDir/sock', type: InternetAddressType.unix)
  ]) {
    await throws(
        () => connectFunction('127.0.0.1', serverIPv4.port,
            sourceAddress: sourceAddress),
        (e) => e is SocketException);
  }
  // Address family mismatch for IPv6.
  for (sourceAddress in [
    '127.0.0.1',
    InternetAddress.loopbackIPv4,
    InternetAddress('$socketDir/sock', type: InternetAddressType.unix)
  ]) {
    await throws(
        () => connectFunction('::1', serverIPv6.port,
            sourceAddress: sourceAddress),
        (e) => e is SocketException);
  }
  // Address family mismatch for Unix domain sockets.
  for (sourceAddress in [
    '127.0.0.1',
    InternetAddress.loopbackIPv4,
    '::1',
    InternetAddress.loopbackIPv6,
  ]) {
    await throws(
        () => connectFunction(
            InternetAddress("$socketDir/sock", type: InternetAddressType.unix),
            serverUnix.port,
            sourceAddress: sourceAddress),
        (e) =>
            e is SocketException &&
            e.toString().contains('Address family not supported'));
  }
  await serverIPv4.close();
  await serverIPv6.close();
  await serverUnix.close();
}

// IPv4 addresses to use as source address when connecting locally.
var ipV4SourceAddresses = [
  InternetAddress.loopbackIPv4,
  InternetAddress.anyIPv4,
  '127.0.0.1',
  '0.0.0.0'
];

// IPv6 addresses to use as source address when connecting locally.
var ipV6SourceAddresses = [
  InternetAddress.loopbackIPv6,
  InternetAddress.anyIPv6,
  '::1',
  '::'
];

Future testConnect(InternetAddress bindAddress, bool v6Only,
    Function connectFunction, Function closeDestroyFunction) async {
  var successCount = 0;
  if (!v6Only) successCount += ipV4SourceAddresses.length;
  if (bindAddress.type == InternetAddressType.IPv6) {
    successCount += ipV6SourceAddresses.length;
  }
  var count = 0;
  var allConnected = new Completer();
  if (successCount == 0) allConnected.complete();

  var server = await ServerSocket.bind(bindAddress, 0, v6Only: v6Only);
  server.listen((s) {
    s.destroy();
    count++;
    if (count == successCount) allConnected.complete();
  });

  // Connect with IPv4 source addresses.
  for (var sourceAddress in ipV4SourceAddresses) {
    if (!v6Only) {
      var s = await connectFunction(InternetAddress.loopbackIPv4, server.port,
          sourceAddress: sourceAddress);
      closeDestroyFunction(s);
    } else {
      // Cannot use an IPv4 source address to connect to IPv6 if
      // v6Only is specified.
      await throws(
          () => connectFunction(InternetAddress.loopbackIPv6, server.port,
              sourceAddress: sourceAddress),
          (e) => e is SocketException);
    }
  }

  // Connect with IPv6 source addresses.
  for (var sourceAddress in ipV6SourceAddresses) {
    if (bindAddress.type == InternetAddressType.IPv6) {
      var s = await connectFunction(InternetAddress.loopbackIPv6, server.port,
          sourceAddress: sourceAddress);
      closeDestroyFunction(s);
    } else {
      // Cannot use an IPv6 source address to connect to IPv4.
      await throws(
          () => connectFunction(InternetAddress.loopbackIPv4, server.port,
              sourceAddress: sourceAddress),
          (e) => e is SocketException);
    }
  }

  await allConnected.future;
  await server.close();
}

main() async {
  await retry(() async {
    await withTempDir('unix_socket_test', (Directory dir) async {
      await testArguments(RawSocket.connect, "${dir.path}");
    });
  });
  await retry(() async {
    await withTempDir('unix_socket_test', (Directory dir) async {
      await testArguments(Socket.connect, "${dir.path}");
    });
  });

  await retry(() async {
    await testConnect(
        InternetAddress.anyIPv4, false, RawSocket.connect, (s) => s.close());
  });
  await retry(() async {
    await testConnect(
        InternetAddress.anyIPv4, false, Socket.connect, (s) => s.destroy());
  });
  await retry(() async {
    await testConnect(
        InternetAddress.anyIPv6, false, RawSocket.connect, (s) => s.close());
  });
  await retry(() async {
    await testConnect(
        InternetAddress.anyIPv6, false, Socket.connect, (s) => s.destroy());
  });
  await retry(() async {
    await testConnect(
        InternetAddress.anyIPv6, true, RawSocket.connect, (s) => s.close());
  });
  await retry(() async {
    await testConnect(
        InternetAddress.anyIPv6, true, Socket.connect, (s) => s.destroy());
  });
}
