示例#1
0
        public async Task ResetConnectionAsync(ConnectionSettings cs, IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            VerifyState(State.Connected);
            if (ServerVersion.Version.CompareTo(ServerVersions.SupportsResetConnection) >= 0)
            {
                await SendAsync(ResetConnectionPayload.Create(), ioBehavior, cancellationToken).ConfigureAwait(false);

                var payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

                OkPayload.Create(payload);

                // the "reset connection" packet also resets the connection charset, so we need to change that back to our default
                payload = new PayloadData(new ArraySegment <byte>(PayloadUtilities.CreateEofStringPayload(CommandKind.Query, "SET NAMES utf8mb4 COLLATE utf8mb4_bin;")));
                await SendAsync(payload, ioBehavior, cancellationToken).ConfigureAwait(false);

                payload = await ReceiveReplyAsync(ioBehavior, 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.CreateAuthenticationResponse(AuthPluginData, 0, cs.Password);
                var payload        = ChangeUserPayload.Create(cs.UserID, hashedPassword, cs.Database);
                await SendAsync(payload, ioBehavior, cancellationToken).ConfigureAwait(false);

                payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

                if (payload.HeaderByte == AuthenticationMethodSwitchRequestPayload.Signature)
                {
                    await SwitchAuthenticationAsync(payload, cs.Password, ioBehavior, cancellationToken);

                    payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
                }
                OkPayload.Create(payload);
            }
        }
示例#2
0
        public void FinishQuerying()
        {
            bool clearConnection = false;

            lock (m_lock)
            {
                if (m_state == State.CancelingQuery)
                {
                    m_state         = State.ClearingPendingCancellation;
                    clearConnection = true;
                }
            }

            if (clearConnection)
            {
                // KILL QUERY will kill a subsequent query if the command it was intended to cancel has already completed.
                // In order to handle this case, we issue a dummy query that will consume the pending cancellation.
                // See https://bugs.mysql.com/bug.php?id=45679
                var payload = new PayloadData(new ArraySegment <byte>(PayloadUtilities.CreateEofStringPayload(CommandKind.Query, "DO SLEEP(0);")));
                SendAsync(payload, IOBehavior.Synchronous, CancellationToken.None).GetAwaiter().GetResult();
                payload = ReceiveReplyAsync(IOBehavior.Synchronous, CancellationToken.None).GetAwaiter().GetResult();
                OkPayload.Create(payload);
            }

            lock (m_lock)
            {
                if (m_state == State.Querying || m_state == State.ClearingPendingCancellation)
                {
                    m_state = State.Connected;
                }
                else
                {
                    VerifyState(State.Failed);
                }
                m_activeCommandId = 0;
            }
        }
示例#3
0
        public async Task <bool> TryPingAsync(IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            VerifyState(State.Connected);

            // send ping payload to verify client and server socket are still connected
            try
            {
                await SendAsync(PingPayload.Create(), ioBehavior, cancellationToken).ConfigureAwait(false);

                var payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

                OkPayload.Create(payload);
                return(true);
            }
            catch (IOException)
            {
            }
            catch (SocketException)
            {
            }

            VerifyState(State.Failed);
            return(false);
        }
示例#4
0
        public async Task ConnectAsync(ConnectionSettings cs, IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            lock (m_lock)
            {
                VerifyState(State.Created);
                m_state = State.Connecting;
            }
            var connected = false;

            if (cs.ConnectionType == ConnectionType.Tcp)
            {
                connected = await OpenTcpSocketAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }
            else if (cs.ConnectionType == ConnectionType.Unix)
            {
                connected = await OpenUnixSocketAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }
            if (!connected)
            {
                lock (m_lock)
                    m_state = State.Failed;
                throw new MySqlException("Unable to connect to any of the specified MySQL hosts.");
            }

            var byteHandler = new SocketByteHandler(m_socket);

            m_payloadHandler = new StandardPayloadHandler(byteHandler);

            var payload = await ReceiveAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

            var reader           = new ByteArrayReader(payload.ArraySegment.Array, payload.ArraySegment.Offset, payload.ArraySegment.Count);
            var initialHandshake = new InitialHandshakePacket(reader);

            // if PluginAuth is supported, then use the specified auth plugin; else, fall back to protocol capabilities to determine the auth type to use
            string authPluginName;

            if ((initialHandshake.ProtocolCapabilities & ProtocolCapabilities.PluginAuth) != 0)
            {
                authPluginName = initialHandshake.AuthPluginName;
            }
            else
            {
                authPluginName = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.SecureConnection) == 0 ? "mysql_old_password" : "mysql_native_password";
            }
            if (authPluginName != "mysql_native_password" && authPluginName != "sha256_password" && authPluginName != "caching_sha2_password")
            {
                throw new NotSupportedException("Authentication method '{0}' is not supported.".FormatInvariant(initialHandshake.AuthPluginName));
            }

            ServerVersion    = new ServerVersion(Encoding.ASCII.GetString(initialHandshake.ServerVersion));
            ConnectionId     = initialHandshake.ConnectionId;
            AuthPluginData   = initialHandshake.AuthPluginData;
            m_useCompression = cs.UseCompression && (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.Compress) != 0;

            var serverSupportsSsl = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.Ssl) != 0;

            if (cs.SslMode != MySqlSslMode.None && (cs.SslMode != MySqlSslMode.Preferred || serverSupportsSsl))
            {
                if (!serverSupportsSsl)
                {
                    throw new MySqlException("Server does not support SSL");
                }
                await InitSslAsync(initialHandshake.ProtocolCapabilities, cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }

            m_supportsConnectionAttributes = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.ConnectionAttributes) != 0;
            if (m_supportsConnectionAttributes && s_connectionAttributes == null)
            {
                s_connectionAttributes = CreateConnectionAttributes();
            }

            m_supportsDeprecateEof = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.DeprecateEof) != 0;

            var response = HandshakeResponse41Packet.Create(initialHandshake, cs, m_useCompression, m_supportsConnectionAttributes ? s_connectionAttributes : null);

            payload = new PayloadData(new ArraySegment <byte>(response));
            await SendReplyAsync(payload, ioBehavior, cancellationToken).ConfigureAwait(false);

            payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

            // if server doesn't support the authentication fast path, it will send a new challenge
            if (payload.HeaderByte == AuthenticationMethodSwitchRequestPayload.Signature)
            {
                payload = await SwitchAuthenticationAsync(cs, payload, ioBehavior, cancellationToken).ConfigureAwait(false);
            }

            OkPayload.Create(payload);

            if (m_useCompression)
            {
                m_payloadHandler = new CompressedPayloadHandler(m_payloadHandler.ByteHandler);
            }
        }
        public async Task ConnectAsync(ConnectionSettings cs, IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            var connected = false;

            if (cs.ConnectionType == ConnectionType.Tcp)
            {
                connected = await OpenTcpSocketAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }
            else if (cs.ConnectionType == ConnectionType.Unix)
            {
                connected = await OpenUnixSocketAsync(cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }
            if (!connected)
            {
                throw new MySqlException("Unable to connect to any of the specified MySQL hosts.");
            }

            var socketByteHandler = new SocketByteHandler(m_socket);

            m_payloadHandler = new StandardPayloadHandler(socketByteHandler);

            var payload = await ReceiveAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

            var reader           = new ByteArrayReader(payload.ArraySegment.Array, payload.ArraySegment.Offset, payload.ArraySegment.Count);
            var initialHandshake = new InitialHandshakePacket(reader);

            // if PluginAuth is supported, then use the specified auth plugin; else, fall back to protocol capabilities to determine the auth type to use
            string authPluginName;

            if ((initialHandshake.ProtocolCapabilities & ProtocolCapabilities.PluginAuth) != 0)
            {
                authPluginName = initialHandshake.AuthPluginName;
            }
            else
            {
                authPluginName = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.SecureConnection) == 0 ? "mysql_old_password" : "mysql_native_password";
            }
            if (authPluginName != "mysql_native_password")
            {
                throw new NotSupportedException("Authentication method '{0}' is not supported.".FormatInvariant(initialHandshake.AuthPluginName));
            }

            ServerVersion  = new ServerVersion(Encoding.ASCII.GetString(initialHandshake.ServerVersion));
            ConnectionId   = initialHandshake.ConnectionId;
            AuthPluginData = initialHandshake.AuthPluginData;
            if (cs.UseCompression && (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.Compress) == 0)
            {
                cs = cs.WithUseCompression(false);
            }

            if (cs.SslMode != MySqlSslMode.None)
            {
                await InitSslAsync(initialHandshake.ProtocolCapabilities, cs, ioBehavior, cancellationToken).ConfigureAwait(false);
            }

            var response = HandshakeResponse41Packet.Create(initialHandshake, cs);

            payload = new PayloadData(new ArraySegment <byte>(response));
            await SendReplyAsync(payload, ioBehavior, cancellationToken).ConfigureAwait(false);

            payload = await ReceiveReplyAsync(ioBehavior, cancellationToken).ConfigureAwait(false);

            OkPayload.Create(payload);

            if (cs.UseCompression)
            {
                m_payloadHandler = new CompressedPayloadHandler(m_payloadHandler.ByteHandler);
            }
        }