Skip to content

Commit

Permalink
feat(DotClient): retry when connection is closed
Browse files Browse the repository at this point in the history
  • Loading branch information
richardschneider committed May 25, 2018
1 parent 4f50dd5 commit ee8f3f6
Showing 1 changed file with 32 additions and 8 deletions.
40 changes: 32 additions & 8 deletions src/DotClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,12 @@ protected override void Dispose(bool disposing)
}
dnsResponse = await tcs.Task.WaitAsync(cts.Token);
}
catch (TaskCanceledException) when (server != null && !server.CanRead)
{
if (log.IsDebugEnabled)
log.Debug($"Retying query #{request.Id}");
return await QueryAsync(request, cancel);
}
finally
{
OutstandingRequests.TryRemove(request.Id, out var _);
Expand Down Expand Up @@ -246,6 +252,16 @@ byte[] BuildRequest(Message request)
paddingOption.Padding = new byte[need];
};

// Keep the connection alive.
if (!opt.Options.Any(o => o.Type == EdnsOptionType.Keepalive))
{
var keepalive = new EdnsKeepaliveOption
{
Timeout = TimeSpan.FromMinutes(2)
};
opt.Options.Add(keepalive);
};

var udpRequest = request.ToByteArray();
byte[] length = BitConverter.GetBytes((ushort)udpRequest.Length);
if (BitConverter.IsLittleEndian)
Expand Down Expand Up @@ -285,8 +301,11 @@ public async Task<Stream> GetDnsServerAsync()
{
var socket = new Socket(endPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
await socket.ConnectAsync(endPoint.Address, endPoint.Port);
var stream = new NetworkStream(socket, ownsSocket: true);

Stream stream = new NetworkStream(socket, ownsSocket: true);
// Better performance with a buffered stream.
#if !NETSTANDARD14
stream = new BufferedStream(stream);
#endif
dnsServer = new SslStream(
stream,
false, // leave inner stream open
Expand Down Expand Up @@ -345,15 +364,13 @@ void ReadResponses(Stream stream)
{
if (log.IsDebugEnabled)
log.Debug("Starting reader thread");
Console.WriteLine("Starting reader thread");

var reader = new DnsReader(stream);
while (stream.CanRead)
{
try
{
var length = reader.ReadUInt16();
Console.WriteLine($"Response length {length}");
// TODO: Check MinLength
if (length > Message.MaxLength)
throw new InvalidDataException("DNS response exceeded max length.");
Expand All @@ -364,31 +381,38 @@ void ReadResponses(Stream stream)
// Find matching request.
if (log.IsDebugEnabled)
log.Debug($"Got response #{response.Id}");
Console.WriteLine($"Got response #{response.Id}");
if (!OutstandingRequests.TryGetValue(response.Id, out var task))
{
log.Warn("DNS response is missing a matching request ID.");
Console.WriteLine("DNS response is missing a matching request ID.");
continue;
}

// Continue the request.
task.SetResult(response);
}
catch (EndOfStreamException)
{
log.Warn("Server closed stream.");
stream.Dispose();
}
catch (Exception e)
{
if (stream.CanRead)
{
log.Error(e);
Console.WriteLine(e.Message);
}
stream.Dispose();
}
}

if (log.IsDebugEnabled)
log.Debug($"Stopping reader thread");
Console.WriteLine($"Stopping reader thread");

// Cancel any outstanding queries.
foreach (var task in OutstandingRequests.Values)
{
task.SetCanceled();
}
}
}

Expand Down

0 comments on commit ee8f3f6

Please sign in to comment.