public override async Task OpenAsync(CancellationToken cancellationToken) { VerifyNotDisposed(); if (State != ConnectionState.Closed) throw new InvalidOperationException("Cannot Open when State is {0}.".FormatInvariant(State)); #if !NETSTANDARD1_3 if (System.Transactions.Transaction.Current != null) throw new NotSupportedException("Ambient transactions are not supported. Use BeginTransaction instead."); #endif if (m_connectionStringBuilder.UseCompression) throw new NotSupportedException("Compression not supported."); SetState(ConnectionState.Connecting); bool success = false; try { var pool = ConnectionPool.GetPool(m_connectionStringBuilder); m_session = pool?.TryGetSession(); if (m_session == null) { m_session = new MySqlSession(pool); var connected = await m_session.ConnectAsync(m_connectionStringBuilder.Server.Split(','), (int) m_connectionStringBuilder.Port).ConfigureAwait(false); if (!connected) { SetState(ConnectionState.Closed); throw new MySqlException("Unable to connect to any of the specified MySQL hosts."); } var payload = await m_session.ReceiveAsync(cancellationToken).ConfigureAwait(false); var reader = new ByteArrayReader(payload.ArraySegment.Array, payload.ArraySegment.Offset, payload.ArraySegment.Count); var initialHandshake = new InitialHandshakePacket(reader); if (initialHandshake.AuthPluginName != "mysql_native_password") throw new NotSupportedException("Only 'mysql_native_password' authentication method is supported."); m_session.ServerVersion = new ServerVersion(Encoding.ASCII.GetString(initialHandshake.ServerVersion)); m_session.AuthPluginData = initialHandshake.AuthPluginData; var response = HandshakeResponse41Packet.Create(initialHandshake, m_connectionStringBuilder.UserID, m_connectionStringBuilder.Password, m_database); payload = new PayloadData(new ArraySegment<byte>(response)); await m_session.SendReplyAsync(payload, cancellationToken).ConfigureAwait(false); await m_session.ReceiveReplyAsync(cancellationToken).ConfigureAwait(false); // TODO: Check success } else if (m_connectionStringBuilder.ConnectionReset) { if (m_session.ServerVersion.Version.CompareTo(ServerVersions.SupportsResetConnection) >= 0) { await m_session.SendAsync(ResetConnectionPayload.Create(), cancellationToken).ConfigureAwait(false); var payload = await m_session.ReceiveReplyAsync(cancellationToken).ConfigureAwait(false); OkPayload.Create(payload); } else { // optimistically hash the password with the challenge from the initial handshake (supported by MariaDB; doesn't appear to be supported by MySQL) var hashedPassword = AuthenticationUtility.HashPassword(m_session.AuthPluginData, 0, m_connectionStringBuilder.Password); var payload = ChangeUserPayload.Create(m_connectionStringBuilder.UserID, hashedPassword, m_database); await m_session.SendAsync(payload, cancellationToken).ConfigureAwait(false); payload = await m_session.ReceiveReplyAsync(cancellationToken).ConfigureAwait(false); if (payload.HeaderByte == AuthenticationMethodSwitchRequestPayload.Signature) { // if the server didn't support the hashed password; rehash with the new challenge var switchRequest = AuthenticationMethodSwitchRequestPayload.Create(payload); if (switchRequest.Name != "mysql_native_password") throw new NotSupportedException("Only 'mysql_native_password' authentication method is supported."); hashedPassword = AuthenticationUtility.HashPassword(switchRequest.Data, 0, m_connectionStringBuilder.Password); payload = new PayloadData(new ArraySegment<byte>(hashedPassword)); await m_session.SendReplyAsync(payload, cancellationToken).ConfigureAwait(false); payload = await m_session.ReceiveReplyAsync(cancellationToken).ConfigureAwait(false); } OkPayload.Create(payload); } } m_hasBeenOpened = true; SetState(ConnectionState.Open); success = true; } catch (MySqlException) { SetState(ConnectionState.Closed); throw; } catch (SocketException ex) { SetState(ConnectionState.Closed); throw new MySqlException("Unable to connect to any of the specified MySQL hosts.", ex); } finally { if (!success) Utility.Dispose(ref m_session); } }
public override async Task OpenAsync(CancellationToken cancellationToken) { VerifyNotDisposed(); if (State != ConnectionState.Closed) { throw new InvalidOperationException("Cannot Open when State is {0}.".FormatInvariant(State)); } #if !NETSTANDARD1_3 if (System.Transactions.Transaction.Current != null) { throw new NotSupportedException("Ambient transactions are not supported. Use BeginTransaction instead."); } #endif SetState(ConnectionState.Connecting); bool success = false; try { // get existing session from the pool if possible var pool = ConnectionPool.GetPool(m_connectionStringBuilder); m_session = pool == null ? null : await pool.TryGetSessionAsync(cancellationToken).ConfigureAwait(false); if (m_session != null) { // test that session is still valid and (optionally) reset it if (!await TryPingAsync(m_session, cancellationToken).ConfigureAwait(false)) { Utility.Dispose(ref m_session); } else if (m_connectionStringBuilder.ConnectionReset) { await ResetConnectionAsync(cancellationToken).ConfigureAwait(false); } } if (m_session == null) { m_session = new MySqlSession(pool); var connected = await m_session.ConnectAsync(m_connectionStringBuilder.Server.Split(','), (int)m_connectionStringBuilder.Port).ConfigureAwait(false); if (!connected) { SetState(ConnectionState.Closed); throw new MySqlException("Unable to connect to any of the specified MySQL hosts."); } var payload = await m_session.ReceiveAsync(cancellationToken).ConfigureAwait(false); var reader = new ByteArrayReader(payload.ArraySegment.Array, payload.ArraySegment.Offset, payload.ArraySegment.Count); var initialHandshake = new InitialHandshakePacket(reader); if (initialHandshake.AuthPluginName != "mysql_native_password") { throw new NotSupportedException("Only 'mysql_native_password' authentication method is supported."); } m_session.ServerVersion = new ServerVersion(Encoding.ASCII.GetString(initialHandshake.ServerVersion)); m_session.AuthPluginData = initialHandshake.AuthPluginData; var response = HandshakeResponse41Packet.Create(initialHandshake, m_connectionStringBuilder.UserID, m_connectionStringBuilder.Password, m_database); payload = new PayloadData(new ArraySegment <byte>(response)); await m_session.SendReplyAsync(payload, cancellationToken).ConfigureAwait(false); await m_session.ReceiveReplyAsync(cancellationToken).ConfigureAwait(false); // TODO: Check success } m_hasBeenOpened = true; SetState(ConnectionState.Open); success = true; } catch (MySqlException) { SetState(ConnectionState.Closed); throw; } catch (SocketException ex) { SetState(ConnectionState.Closed); throw new MySqlException("Unable to connect to any of the specified MySQL hosts.", ex); } finally { if (!success) { Utility.Dispose(ref m_session); } } }
public override async Task OpenAsync(CancellationToken cancellationToken) { VerifyNotDisposed(); if (State != ConnectionState.Closed) { throw new InvalidOperationException("Cannot Open when State is {0}.".FormatInvariant(State)); } #if !NETSTANDARD1_3 if (System.Transactions.Transaction.Current != null) { throw new NotSupportedException("Ambient transactions are not supported. Use BeginTransaction instead."); } #endif if (m_connectionStringBuilder.UseCompression) { throw new NotSupportedException("Compression not supported."); } SetState(ConnectionState.Connecting); bool success = false; try { var pool = ConnectionPool.GetPool(m_connectionStringBuilder); m_session = pool?.TryGetSession(); if (m_session == null) { m_session = new MySqlSession(pool); var connected = await m_session.ConnectAsync(m_connectionStringBuilder.Server.Split(','), (int)m_connectionStringBuilder.Port).ConfigureAwait(false); if (!connected) { SetState(ConnectionState.Closed); throw new MySqlException("Unable to connect to any of the specified MySQL hosts."); } var payload = await m_session.ReceiveAsync(cancellationToken).ConfigureAwait(false); var reader = new ByteArrayReader(payload.ArraySegment.Array, payload.ArraySegment.Offset, payload.ArraySegment.Count); var initialHandshake = new InitialHandshakePacket(reader); if (initialHandshake.AuthPluginName != "mysql_native_password") { throw new NotSupportedException("Only 'mysql_native_password' authentication method is supported."); } m_session.ServerVersion = new ServerVersion(Encoding.ASCII.GetString(initialHandshake.ServerVersion)); var response = HandshakeResponse41Packet.Create(initialHandshake, m_connectionStringBuilder.UserID, m_connectionStringBuilder.Password, m_database); payload = new PayloadData(new ArraySegment <byte>(response)); await m_session.SendReplyAsync(payload, cancellationToken).ConfigureAwait(false); await m_session.ReceiveReplyAsync(cancellationToken).ConfigureAwait(false); // TODO: Check success } else if (m_connectionStringBuilder.ConnectionReset) { if (m_session.ServerVersion.Version.CompareTo(ServerVersions.SupportsResetConnection) >= 0) { await m_session.SendAsync(ResetConnectionPayload.Create(), cancellationToken).ConfigureAwait(false); var payload = await m_session.ReceiveReplyAsync(cancellationToken); OkPayload.Create(payload); } else { // MySQL doesn't appear to accept a replayed hashed password (using the challenge from the initial handshake), so just send zeroes // and expect to get a new challenge var payload = ChangeUserPayload.Create(m_connectionStringBuilder.UserID, new byte[20], m_database); await m_session.SendAsync(payload, cancellationToken).ConfigureAwait(false); payload = await m_session.ReceiveReplyAsync(cancellationToken).ConfigureAwait(false); var switchRequest = AuthenticationMethodSwitchRequestPayload.Create(payload); if (switchRequest.Name != "mysql_native_password") { throw new NotSupportedException("Only 'mysql_native_password' authentication method is supported."); } var hashedPassword = AuthenticationUtility.HashPassword(switchRequest.Data, 0, m_connectionStringBuilder.Password); payload = new PayloadData(new ArraySegment <byte>(hashedPassword)); await m_session.SendReplyAsync(payload, cancellationToken).ConfigureAwait(false); payload = await m_session.ReceiveReplyAsync(cancellationToken).ConfigureAwait(false); OkPayload.Create(payload); } } m_hasBeenOpened = true; SetState(ConnectionState.Open); success = true; } catch (MySqlException) { SetState(ConnectionState.Closed); throw; } catch (SocketException ex) { SetState(ConnectionState.Closed); throw new MySqlException("Unable to connect to any of the specified MySQL hosts.", ex); } finally { if (!success) { Utility.Dispose(ref m_session); } } }