Skip to content

Commit dbd9d1e

Browse files
committed
Add timeout for named pipe connections. Fixes #804
1 parent 00d2090 commit dbd9d1e

File tree

2 files changed

+48
-6
lines changed

2 files changed

+48
-6
lines changed

src/MySqlConnector/Core/ServerSession.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ public async Task ConnectAsync(ConnectionSettings cs, int startTickCount, ILoadB
340340
else if (cs.ConnectionProtocol == MySqlConnectionProtocol.UnixSocket)
341341
connected = await OpenUnixSocketAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
342342
else if (cs.ConnectionProtocol == MySqlConnectionProtocol.NamedPipe)
343-
connected = await OpenNamedPipeAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
343+
connected = await OpenNamedPipeAsync(cs, startTickCount, ioBehavior, cancellationToken).ConfigureAwait(false);
344344
if (!connected)
345345
{
346346
lock (m_lock)
@@ -981,23 +981,35 @@ private async Task<bool> OpenUnixSocketAsync(ConnectionSettings cs, IOBehavior i
981981
return false;
982982
}
983983

984-
private Task<bool> OpenNamedPipeAsync(ConnectionSettings cs, IOBehavior ioBehavior, CancellationToken cancellationToken)
984+
#if NET45 || NETSTANDARD1_3
985+
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
986+
#endif
987+
private async Task<bool> OpenNamedPipeAsync(ConnectionSettings cs, int startTickCount, IOBehavior ioBehavior, CancellationToken cancellationToken)
988+
#if NET45 || NETSTANDARD1_3Co
989+
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
990+
#endif
985991
{
986992
#if NETSTANDARD1_3
987993
throw new NotSupportedException("Named pipe connections are not supported in netstandard1.3");
988994
#else
989995
if (Log.IsInfoEnabled())
990996
Log.Info("Session{0} connecting to NamedPipe '{1}' on Server '{2}'", m_logArguments[0], cs.PipeName, cs.HostNames![0]);
991997
var namedPipeStream = new NamedPipeClientStream(cs.HostNames![0], cs.PipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
998+
var timeout = Math.Max(1, cs.ConnectionTimeoutMilliseconds - unchecked(Environment.TickCount - startTickCount));
992999
try
9931000
{
9941001
using (cancellationToken.Register(() => namedPipeStream.Dispose()))
9951002
{
9961003
try
9971004
{
998-
namedPipeStream.Connect();
1005+
#if !NET45
1006+
if (ioBehavior == IOBehavior.Asynchronous)
1007+
await namedPipeStream.ConnectAsync(timeout, cancellationToken).ConfigureAwait(false);
1008+
else
1009+
#endif
1010+
namedPipeStream.Connect(timeout);
9991011
}
1000-
catch (ObjectDisposedException ex) when (cancellationToken.IsCancellationRequested)
1012+
catch (Exception ex) when ((ex is ObjectDisposedException && cancellationToken.IsCancellationRequested) || ex is TimeoutException)
10011013
{
10021014
m_logArguments[1] = cs.PipeName;
10031015
Log.Info("Session{0} connect timeout expired connecting to named pipe '{1}'", m_logArguments);
@@ -1016,10 +1028,10 @@ private Task<bool> OpenNamedPipeAsync(ConnectionSettings cs, IOBehavior ioBehavi
10161028

10171029
lock (m_lock)
10181030
m_state = State.Connected;
1019-
return Task.FromResult(true);
1031+
return true;
10201032
}
10211033

1022-
return Task.FromResult(false);
1034+
return false;
10231035
#endif
10241036
}
10251037

tests/SideBySide/ConnectSync.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,36 @@ public void LoadBalanceNotSupported(string connectionString)
123123
}
124124
#endif
125125

126+
#if !NETCOREAPP1_1_2
127+
[Fact]
128+
public void NonExistentPipe()
129+
{
130+
var csb = new MySqlConnectionStringBuilder
131+
{
132+
PipeName = "nonexistingpipe",
133+
ConnectionProtocol = MySqlConnectionProtocol.NamedPipe,
134+
Server = ".",
135+
ConnectionTimeout = 1
136+
};
137+
138+
var sw = Stopwatch.StartNew();
139+
using var connection = new MySqlConnection(csb.ConnectionString);
140+
try
141+
{
142+
connection.Open();
143+
Assert.False(true);
144+
}
145+
catch (MySqlException)
146+
{
147+
}
148+
#if !BASELINE
149+
TestUtilities.AssertDuration(sw, 900, 500);
150+
#else
151+
TestUtilities.AssertDuration(sw, 0, 500);
152+
#endif
153+
}
154+
#endif
155+
126156
[Theory]
127157
[InlineData(false, false)]
128158
[InlineData(true, false)]

0 commit comments

Comments
 (0)