amphp / mysql

An async MySQL client for PHP, optimizing database interactions with efficient non-blocking capabilities. Perfect for responsive, high-performance applications.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unable to connect to AWS Aurora MySQL 3.04.0 (MySQL 8.0.28) over TLS

GrahamCampbell opened this issue · comments

Code to make the connection pool:

            $config = [/* OMITTED */];

            $tlsContext = (new ClientTlsContext())
                ->withCaFile($config['options'][PDO::MYSQL_ATTR_SSL_CA] ?? null);

            return new MysqlConnectionPool(
                new MysqlConfig(
                    $config['host'],
                    (int) $config['port'],
                    $config['username'],
                    $config['password'],
                    $config['database'],
                    (new ConnectContext())->withTlsContext($tlsContext),
                    $config['charset'],
                    $config['collation'],
                ),
            );

Then, the folowing code hangs forever trying to establish a connection, despite the default connect timeout being 10 seconds.

        foreach ($this->db->query('SELECT 1 AS value') as $row) {
            var_dump($row['value']);
        }

Digging into the code, we're getting stuck at:

                        $connection = (
                            $this->future = async(fn () => $this->connector->connect($this->config))
                        )->await();

on line 243 of Amp\Sql\CommonConnectionPool.

Digging further, it's the call to Amp\Mysql\SocketMysqlConnection::initialize which is hanging. Indeed, the $future->await() call on line 228 of Amp\Mysql\Internal\ConnectionProcessor::connect.


Installed versions:

PHP 8.2.8 (cli) (built: Jul  6 2023 10:57:44) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.8, Copyright (c) Zend Technologies
    with Zend OPcache v8.2.8, Copyright (c), by Zend Technologies

amphp/amp                          v3.0.0
amphp/byte-stream                  v2.0.1
amphp/cache                        v2.0.0
amphp/dns                          v2.0.1
amphp/mysql                        v3.0.0-beta.6
amphp/parser                       v1.1.0
amphp/pipeline                     v1.0.0
amphp/process                      v2.0.1
amphp/serialization                v1.0.0
amphp/socket                       v2.1.0
amphp/sql                          v2.0.0-beta.4
amphp/sql-common                   v2.0.0-beta.6
amphp/sync                         v2.0.0
amphp/windows-registry             v1.0.0

It looks like the server side is complaining of a bad handshake from the client.

[Note] [MY-010914] [Server] Bad handshake

It looks like stream_socket_enable_crypto inside of the call to setupTls keeps returning 0.

            EventLoop::queue(function () use ($payload): void {
                try {
                    $this->write(\implode($payload));

                    $this->socket->setupTls();

                    $this->sendHandshake(true);
                } catch (\Throwable $e) {
                    $this->free($e);
                }
            });

It looks like we end up hanging forever because $suspension->suspend(); waits forever after a couple of trips around the while, I guess because the server is done sending bytes, after deciding the client is not behaving itself.

    while (true) {
        $cancellation->throwIfRequested();

        $suspension = EventLoop::getSuspension();

        // Watcher is guaranteed to be created, because we throw above if cancellation has already been requested
        $cancellationId = $cancellation->subscribe(static function ($e) use ($suspension, &$callbackId): void {
            EventLoop::cancel($callbackId);

            $suspension->throw($e);
        });

        $callbackId = EventLoop::onReadable($socket, static function () use (
            $suspension,
            $cancellation,
            $cancellationId,
        ): void {
            $cancellation->unsubscribe($cancellationId);

            $suspension->resume();
        });

        try {
            $suspension->suspend();
        } finally {
            EventLoop::cancel($callbackId);
        }

        try {
            \set_error_handler($errorHandler);
            $result = \stream_socket_enable_crypto($socket, enable: true);
            if ($result === false) {
                $message = \feof($socket) ? 'Connection reset by peer' : 'Unknown error';
                throw new TlsException('TLS negotiation failed: ' . $message);
            }
        } finally {
            \restore_error_handler();
        }

        // If $result is 0, just wait for the next invocation
        if ($result === true) {
            break;
        }
    }

@bwoebi Do you have any idea what might be going on here with TLS?

@GrahamCampbell I realize it's been quite some time since you opened this issue, but would you be able to try again with the latest dev-3.x. I found an issue with connecting with TLS which may have been preventing a proper handshake.