Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/fluiver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ library;

import 'dart:async';
import 'dart:collection';
import 'dart:io' show InternetAddress, Socket, SocketException;
import 'dart:io' show InternetAddress, SecureSocket, SocketException;

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
Expand Down
8 changes: 4 additions & 4 deletions lib/src/helpers/network_probe.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ part of '../../fluiver.dart';

/// Lightweight reachability probes.
abstract final class NetworkProbe {
/// Returns `true` if a TCP socket to `host:port` — Cloudflare DNS
/// (`1.0.0.1:53`) by default — opens within [timeout].
/// Returns `true` if a secure connection to `host:port` — Cloudflare DNS
/// over TLS (`1.0.0.1:853`) by default — opens within [timeout].
///
/// Skips DNS resolution by connecting to a literal IP — faster and more
/// reliable than HTTP probes. [host] must be a literal IPv4/IPv6 address;
Expand All @@ -20,14 +20,14 @@ abstract final class NetworkProbe {
/// in the browser, and a running web app is by definition online.
static Future<bool> checkConnection({
String host = '1.0.0.1',
int port = 53,
int port = 853,
Duration timeout = const Duration(seconds: 3),
}) async {
if (kIsWeb) {
return true;
}
try {
final socket = await Socket.connect(
final socket = await SecureSocket.connect(
InternetAddress(host),
port,
timeout: timeout,
Expand Down
17 changes: 4 additions & 13 deletions test/network_probe_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,20 @@ import 'package:fluiver/fluiver.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
// The TimeoutException path is not covered: a deterministic connect
// timeout needs an endpoint that black-holes SYNs, and no loopback setup
// does that — closed ports refuse (SocketException) instead.
group('checkConnection', () {
test('returns true when the endpoint accepts', () async {
final server = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0);
addTearDown(server.close);

// Connect to Google DNS over TLS as an integration test.
// This avoids mocking a local secure server without valid certificates.
final result = await NetworkProbe.checkConnection(
host: server.address.address,
port: server.port,
host: '8.8.8.8',
);
check(result).isTrue();
});

test('returns false on connection refused', () async {
final server = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0);
final port = server.port;
await server.close();

final result = await NetworkProbe.checkConnection(
host: InternetAddress.loopbackIPv4.address,
port: port,
port: 55555,
);
check(result).isFalse();
});
Expand Down