ping static method

Future<IcmpResult?> ping(
  1. InternetAddress ipv4Address, {
  2. Duration timeout = const Duration(seconds: 1),
  3. int sizeToSend = 32,
  4. int replyBufferSize = 1024,
})

Implementation

static Future<IcmpResult?> ping(
  InternetAddress ipv4Address, {
  Duration timeout = const Duration(seconds: 1),
  int sizeToSend = 32,
  int replyBufferSize = 1024,
}) async {
  if (ipv4Address.type != InternetAddressType.IPv4) {
    throw Exception('Only IPv4 address is supported');
  }
  final ipv4 = ipv4Address.rawAddress;
  final ipv4int =
      (ipv4[3] << 24) | (ipv4[2] << 16) | (ipv4[1] << 8) | ipv4[0];

  final hEvent = _Kernel32.createEvent(0, 1, 0, 0);
  final toSend = calloc<Uint8>(sizeToSend);
  final replyBuffer = calloc<_ICMP_ECHO_REPLY>(replyBufferSize);
  final icmp = _IcmpApi.icmpOpenFile();
  const WAIT_TIMEOUT = 0x102;
  const ERROR_IO_PENDING = 997;

  try {
    final result = _IcmpApi.icmpSendEcho2(
      icmp,
      hEvent,
      0,
      0,
      ipv4int,
      toSend,
      sizeToSend,
      0,
      replyBuffer,
      replyBufferSize,
      timeout.inMilliseconds,
    );
    if (result != 0) return null;
    // final error = _Kernel32.getLastError();
    // if (error != ERROR_IO_PENDING) return null;

    for (;;) {
      final result = _Kernel32.waitForSingleObject(hEvent, 0);
      if (result == 0) {
        final result = replyBuffer.ref;
        return IcmpResult(
            status: result.status,
            roundTripTime: Duration(milliseconds: result.roundTripTime),
            ttl: result.ttl);
      } else if (result != WAIT_TIMEOUT) {
        return null;
      }
      await Future.delayed(
          Duration(milliseconds: min(100, timeout.inMilliseconds)));
    }
  } finally {
    _IcmpApi.icmpCloseHandle(icmp);
    calloc.free(toSend);
    calloc.free(replyBuffer);
    _Kernel32.closeHandle(hEvent);
  }
}