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.