Skip to content

Commit

Permalink
Add timeout for named pipe connections. Fixes #804
Browse files Browse the repository at this point in the history
  • Loading branch information
bgrainger committed Apr 26, 2020
1 parent 00d2090 commit dbd9d1e
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 6 deletions.
24 changes: 18 additions & 6 deletions src/MySqlConnector/Core/ServerSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ public async Task ConnectAsync(ConnectionSettings cs, int startTickCount, ILoadB
else if (cs.ConnectionProtocol == MySqlConnectionProtocol.UnixSocket)
connected = await OpenUnixSocketAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
else if (cs.ConnectionProtocol == MySqlConnectionProtocol.NamedPipe)
connected = await OpenNamedPipeAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
connected = await OpenNamedPipeAsync(cs, startTickCount, ioBehavior, cancellationToken).ConfigureAwait(false);
if (!connected)
{
lock (m_lock)
Expand Down Expand Up @@ -981,23 +981,35 @@ private async Task<bool> OpenUnixSocketAsync(ConnectionSettings cs, IOBehavior i
return false;
}

private Task<bool> OpenNamedPipeAsync(ConnectionSettings cs, IOBehavior ioBehavior, CancellationToken cancellationToken)
#if NET45 || NETSTANDARD1_3
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
#endif
private async Task<bool> OpenNamedPipeAsync(ConnectionSettings cs, int startTickCount, IOBehavior ioBehavior, CancellationToken cancellationToken)
#if NET45 || NETSTANDARD1_3Co
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
#endif
{
#if NETSTANDARD1_3
throw new NotSupportedException("Named pipe connections are not supported in netstandard1.3");
#else
if (Log.IsInfoEnabled())
Log.Info("Session{0} connecting to NamedPipe '{1}' on Server '{2}'", m_logArguments[0], cs.PipeName, cs.HostNames![0]);
var namedPipeStream = new NamedPipeClientStream(cs.HostNames![0], cs.PipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
var timeout = Math.Max(1, cs.ConnectionTimeoutMilliseconds - unchecked(Environment.TickCount - startTickCount));
try
{
using (cancellationToken.Register(() => namedPipeStream.Dispose()))
{
try
{
namedPipeStream.Connect();
#if !NET45
if (ioBehavior == IOBehavior.Asynchronous)
await namedPipeStream.ConnectAsync(timeout, cancellationToken).ConfigureAwait(false);
else
#endif
namedPipeStream.Connect(timeout);
}
catch (ObjectDisposedException ex) when (cancellationToken.IsCancellationRequested)
catch (Exception ex) when ((ex is ObjectDisposedException && cancellationToken.IsCancellationRequested) || ex is TimeoutException)
{
m_logArguments[1] = cs.PipeName;
Log.Info("Session{0} connect timeout expired connecting to named pipe '{1}'", m_logArguments);
Expand All @@ -1016,10 +1028,10 @@ private Task<bool> OpenNamedPipeAsync(ConnectionSettings cs, IOBehavior ioBehavi

lock (m_lock)
m_state = State.Connected;
return Task.FromResult(true);
return true;
}

return Task.FromResult(false);
return false;
#endif
}

Expand Down
30 changes: 30 additions & 0 deletions tests/SideBySide/ConnectSync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,36 @@ public void LoadBalanceNotSupported(string connectionString)
}
#endif

#if !NETCOREAPP1_1_2
[Fact]
public void NonExistentPipe()
{
var csb = new MySqlConnectionStringBuilder
{
PipeName = "nonexistingpipe",
ConnectionProtocol = MySqlConnectionProtocol.NamedPipe,
Server = ".",
ConnectionTimeout = 1
};

var sw = Stopwatch.StartNew();
using var connection = new MySqlConnection(csb.ConnectionString);
try
{
connection.Open();
Assert.False(true);
}
catch (MySqlException)
{
}
#if !BASELINE
TestUtilities.AssertDuration(sw, 900, 500);
#else
TestUtilities.AssertDuration(sw, 0, 500);
#endif
}
#endif

[Theory]
[InlineData(false, false)]
[InlineData(true, false)]
Expand Down

0 comments on commit dbd9d1e

Please sign in to comment.