예제 #1
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")
            {
                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();
            }

            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)
            {
                await SwitchAuthenticationAsync(cs, payload, ioBehavior, cancellationToken).ConfigureAwait(false);

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

            OkPayload.Create(payload);

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