Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ public class TestConnectionCommand : PSCmdlet, IDisposable

private static byte[]? s_DefaultSendBuffer;

private readonly CancellationTokenSource _dnsLookupCancel = new CancellationTokenSource();

private bool _disposed;

private Ping? _sender;
Expand Down Expand Up @@ -275,6 +277,7 @@ protected override void ProcessRecord()
protected override void StopProcessing()
{
_sender?.SendAsyncCancel();
_dnsLookupCancel.Cancel();
}

#region ConnectionTest
Expand All @@ -283,6 +286,11 @@ private void ProcessConnectionByTCPPort(string targetNameOrAddress)
{
if (!TryResolveNameOrAddress(targetNameOrAddress, out _, out IPAddress? targetAddress))
{
if (Quiet.IsPresent)
{
WriteObject(false);
}

return;
}

Expand Down Expand Up @@ -334,6 +342,11 @@ private void ProcessTraceroute(string targetNameOrAddress)

if (!TryResolveNameOrAddress(targetNameOrAddress, out string resolvedTargetName, out IPAddress? targetAddress))
{
if (!Quiet.IsPresent)
{
WriteObject(false);
}

return;
}

Expand Down Expand Up @@ -471,6 +484,11 @@ private void ProcessMTUSize(string targetNameOrAddress)
PingReply? reply, replyResult = null;
if (!TryResolveNameOrAddress(targetNameOrAddress, out string resolvedTargetName, out IPAddress? targetAddress))
{
if (Quiet.IsPresent)
{
WriteObject(-1);
}

return;
}

Expand Down Expand Up @@ -574,6 +592,11 @@ private void ProcessPing(string targetNameOrAddress)
{
if (!TryResolveNameOrAddress(targetNameOrAddress, out string resolvedTargetName, out IPAddress? targetAddress))
{
if (Quiet.IsPresent)
{
WriteObject(false);
}

return;
}

Expand Down Expand Up @@ -667,7 +690,7 @@ private bool TryResolveNameOrAddress(

if (ResolveDestination)
{
hostEntry = Dns.GetHostEntry(targetNameOrAddress);
hostEntry = GetCancellableHostEntry(targetNameOrAddress);
resolvedTargetName = hostEntry.HostName;
}
else
Expand All @@ -679,27 +702,35 @@ private bool TryResolveNameOrAddress(
{
try
{
hostEntry = Dns.GetHostEntry(targetNameOrAddress);
hostEntry = GetCancellableHostEntry(targetNameOrAddress);

if (ResolveDestination)
{
resolvedTargetName = hostEntry.HostName;
hostEntry = Dns.GetHostEntry(hostEntry.HostName);
hostEntry = GetCancellableHostEntry(hostEntry.HostName);
}
}
catch (PipelineStoppedException)
{
throw;
}
catch (Exception ex)
{
string message = StringUtil.Format(
TestConnectionResources.NoPingResult,
resolvedTargetName,
TestConnectionResources.CannotResolveTargetName);
Exception pingException = new PingException(message, ex);
ErrorRecord errorRecord = new ErrorRecord(
pingException,
TestConnectionExceptionId,
ErrorCategory.ResourceUnavailable,
resolvedTargetName);
WriteError(errorRecord);
if (!Quiet.IsPresent)
{
string message = StringUtil.Format(
TestConnectionResources.NoPingResult,
resolvedTargetName,
TestConnectionResources.CannotResolveTargetName);
Exception pingException = new PingException(message, ex);
ErrorRecord errorRecord = new ErrorRecord(
pingException,
TestConnectionExceptionId,
ErrorCategory.ResourceUnavailable,
resolvedTargetName);
WriteError(errorRecord);
}

return false;
}

Expand Down Expand Up @@ -732,6 +763,20 @@ private bool TryResolveNameOrAddress(
return true;
}

private IPHostEntry GetCancellableHostEntry(string targetNameOrAddress)
{
var task = Dns.GetHostEntryAsync(targetNameOrAddress);
var waitHandles = new[] { ((IAsyncResult)task).AsyncWaitHandle, _dnsLookupCancel.Token.WaitHandle };

// WaitAny() returns the index of the first signal it gets; 1 is our cancellation token.
if (WaitHandle.WaitAny(waitHandles) == 1)
{
throw new PipelineStoppedException();
}

return task.GetAwaiter().GetResult();
}

private IPAddress? GetHostAddress(IPHostEntry hostEntry)
{
AddressFamily addressFamily = IPv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,19 @@ Describe "Test-Connection" -tags "CI" {
$result2 | Should -BeFalse
}

It "Ping fake host" {
It 'returns false without errors for an unresolvable address when using -Quiet' {
Test-Connection -Quiet -ErrorAction Stop -Count 1 -TargetName "fakeHost" | Should -BeFalse
}

{ $result = Test-Connection "fakeHost" -Count 1 -Quiet -ErrorAction Stop } |
It "Ping fake host" {
{ Test-Connection "fakeHost" -Count 1 -ErrorAction Stop } |
Should -Throw -ErrorId "TestConnectionException,Microsoft.PowerShell.Commands.TestConnectionCommand"
# Error code = 11001 - Host not found.
if ((Get-PlatformInfo).Platform -match "raspbian") {
$code = 11
}
elseif (!$IsWindows) {
} elseif (!$IsWindows) {
$code = -131073
}
else {
} else {
$code = 11001
}
$error[0].Exception.InnerException.ErrorCode | Should -Be $code
Expand Down