@@ -422,157 +422,106 @@ public async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancella
422
422
}
423
423
}
424
424
425
- // TLS negotiation should automatically fall back to the best version supported by client and server. However,
426
- // Windows Schannel clients will fail to connect to a yaSSL-based MySQL Server if TLS 1.2 is requested and
427
- // have to use only TLS 1.1: https://github.com/mysql-net/MySqlConnector/pull/101
428
- // In order to use the best protocol possible (i.e., not always default to TLS 1.1), we try the OS-default protocol
429
- // (which is SslProtocols.None; see https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls),
430
- // then fall back to SslProtocols.Tls11 if that fails and it's possible that the cause is a yaSSL server.
431
- bool shouldRetrySsl ;
432
- var shouldUpdatePoolSslProtocols = false ;
433
- var sslProtocols = Pool ? . SslProtocols ?? cs . TlsVersions ;
434
- PayloadData payload ;
435
- InitialHandshakePayload initialHandshake ;
436
- do
425
+ var connected = false ;
426
+ if ( cs . ConnectionProtocol == MySqlConnectionProtocol . Sockets )
427
+ connected = await OpenTcpSocketAsync ( cs , loadBalancer ?? throw new ArgumentNullException ( nameof ( loadBalancer ) ) , activity , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
428
+ else if ( cs . ConnectionProtocol == MySqlConnectionProtocol . UnixSocket )
429
+ connected = await OpenUnixSocketAsync ( cs , activity , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
430
+ else if ( cs . ConnectionProtocol == MySqlConnectionProtocol . NamedPipe )
431
+ connected = await OpenNamedPipeAsync ( cs , startingTimestamp , activity , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
432
+ if ( ! connected )
437
433
{
438
- var isTls11or10Supported = ( sslProtocols & ( SslProtocols . Tls | SslProtocols . Tls11 ) ) != SslProtocols . None ;
439
- var isTls12Supported = ( sslProtocols & SslProtocols . Tls12 ) == SslProtocols . Tls12 ;
440
- shouldRetrySsl = ( sslProtocols == SslProtocols . None || ( isTls12Supported && isTls11or10Supported ) ) && Utility . IsWindows ( ) ;
441
-
442
- var connected = false ;
443
- if ( cs . ConnectionProtocol == MySqlConnectionProtocol . Sockets )
444
- connected = await OpenTcpSocketAsync ( cs , loadBalancer ?? throw new ArgumentNullException ( nameof ( loadBalancer ) ) , activity , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
445
- else if ( cs . ConnectionProtocol == MySqlConnectionProtocol . UnixSocket )
446
- connected = await OpenUnixSocketAsync ( cs , activity , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
447
- else if ( cs . ConnectionProtocol == MySqlConnectionProtocol . NamedPipe )
448
- connected = await OpenNamedPipeAsync ( cs , startingTimestamp , activity , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
449
- if ( ! connected )
450
- {
451
- lock ( m_lock )
452
- m_state = State . Failed ;
453
- Log . ConnectingFailed ( m_logger , Id ) ;
454
- throw new MySqlException ( MySqlErrorCode . UnableToConnectToHost , "Unable to connect to any of the specified MySQL hosts." ) ;
455
- }
434
+ lock ( m_lock )
435
+ m_state = State . Failed ;
436
+ Log . ConnectingFailed ( m_logger , Id ) ;
437
+ throw new MySqlException ( MySqlErrorCode . UnableToConnectToHost , "Unable to connect to any of the specified MySQL hosts." ) ;
438
+ }
456
439
457
- var byteHandler = m_socket is null ? new StreamByteHandler ( m_stream ! ) : ( IByteHandler ) new SocketByteHandler ( m_socket ) ;
458
- if ( cs . ConnectionTimeout != 0 )
459
- byteHandler . RemainingTimeout = Math . Max ( 1 , cs . ConnectionTimeoutMilliseconds - Utility . GetElapsedMilliseconds ( startingTimestamp ) ) ;
460
- m_payloadHandler = new StandardPayloadHandler ( byteHandler ) ;
440
+ var byteHandler = m_socket is null ? new StreamByteHandler ( m_stream ! ) : ( IByteHandler ) new SocketByteHandler ( m_socket ) ;
441
+ if ( cs . ConnectionTimeout != 0 )
442
+ byteHandler . RemainingTimeout = Math . Max ( 1 , cs . ConnectionTimeoutMilliseconds - Utility . GetElapsedMilliseconds ( startingTimestamp ) ) ;
443
+ m_payloadHandler = new StandardPayloadHandler ( byteHandler ) ;
461
444
462
- payload = await ReceiveAsync ( ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
463
- initialHandshake = InitialHandshakePayload . Create ( payload . Span ) ;
445
+ var payload = await ReceiveAsync ( ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
446
+ var initialHandshake = InitialHandshakePayload . Create ( payload . Span ) ;
464
447
465
- // if PluginAuth is supported, then use the specified auth plugin; else, fall back to protocol capabilities to determine the auth type to use
466
- string authPluginName ;
467
- if ( ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . PluginAuth ) != 0 )
468
- authPluginName = initialHandshake . AuthPluginName ! ;
469
- else
470
- authPluginName = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . SecureConnection ) == 0 ? "mysql_old_password" : "mysql_native_password" ;
471
- Log . ServerSentAuthPluginName ( m_logger , Id , authPluginName ) ;
472
- if ( authPluginName != "mysql_native_password" && authPluginName != "sha256_password" && authPluginName != "caching_sha2_password" )
473
- {
474
- Log . UnsupportedAuthenticationMethod ( m_logger , Id , authPluginName ) ;
475
- throw new NotSupportedException ( $ "Authentication method '{ initialHandshake . AuthPluginName } ' is not supported.") ;
476
- }
448
+ // if PluginAuth is supported, then use the specified auth plugin; else, fall back to protocol capabilities to determine the auth type to use
449
+ string authPluginName ;
450
+ if ( ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . PluginAuth ) != 0 )
451
+ authPluginName = initialHandshake . AuthPluginName ! ;
452
+ else
453
+ authPluginName = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . SecureConnection ) == 0 ? "mysql_old_password" : "mysql_native_password" ;
454
+ Log . ServerSentAuthPluginName ( m_logger , Id , authPluginName ) ;
455
+ if ( authPluginName != "mysql_native_password" && authPluginName != "sha256_password" && authPluginName != "caching_sha2_password" )
456
+ {
457
+ Log . UnsupportedAuthenticationMethod ( m_logger , Id , authPluginName ) ;
458
+ throw new NotSupportedException ( $ "Authentication method '{ initialHandshake . AuthPluginName } ' is not supported.") ;
459
+ }
477
460
478
- ServerVersion = new ( initialHandshake . ServerVersion ) ;
479
- ConnectionId = initialHandshake . ConnectionId ;
480
- AuthPluginData = initialHandshake . AuthPluginData ;
481
- m_useCompression = cs . UseCompression && ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . Compress ) != 0 ;
482
- CancellationTimeout = cs . CancellationTimeout ;
483
- UserID = cs . UserID ;
461
+ ServerVersion = new ( initialHandshake . ServerVersion ) ;
462
+ ConnectionId = initialHandshake . ConnectionId ;
463
+ AuthPluginData = initialHandshake . AuthPluginData ;
464
+ m_useCompression = cs . UseCompression && ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . Compress ) != 0 ;
465
+ CancellationTimeout = cs . CancellationTimeout ;
466
+ UserID = cs . UserID ;
484
467
485
- // set activity tags
486
- {
487
- var connectionId = ConnectionId . ToString ( CultureInfo . InvariantCulture ) ;
488
- m_activityTags [ ActivitySourceHelper . DatabaseConnectionIdTagName ] = connectionId ;
489
- if ( activity is { IsAllDataRequested : true } )
490
- activity . SetTag ( ActivitySourceHelper . DatabaseConnectionIdTagName , connectionId ) ;
491
- }
468
+ // set activity tags
469
+ {
470
+ var connectionId = ConnectionId . ToString ( CultureInfo . InvariantCulture ) ;
471
+ m_activityTags [ ActivitySourceHelper . DatabaseConnectionIdTagName ] = connectionId ;
472
+ if ( activity is { IsAllDataRequested : true } )
473
+ activity . SetTag ( ActivitySourceHelper . DatabaseConnectionIdTagName , connectionId ) ;
474
+ }
492
475
493
- m_supportsConnectionAttributes = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . ConnectionAttributes ) != 0 ;
494
- m_supportsDeprecateEof = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . DeprecateEof ) != 0 ;
495
- SupportsCachedPreparedMetadata = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . MariaDbCacheMetadata ) != 0 ;
496
- SupportsQueryAttributes = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . QueryAttributes ) != 0 ;
497
- m_supportsSessionTrack = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . SessionTrack ) != 0 ;
498
- var serverSupportsSsl = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . Ssl ) != 0 ;
499
- m_characterSet = ServerVersion . Version >= ServerVersions . SupportsUtf8Mb4 ? CharacterSet . Utf8Mb4GeneralCaseInsensitive : CharacterSet . Utf8Mb3GeneralCaseInsensitive ;
500
- m_setNamesPayload = ServerVersion . Version >= ServerVersions . SupportsUtf8Mb4 ?
501
- ( SupportsQueryAttributes ? s_setNamesUtf8mb4WithAttributesPayload : s_setNamesUtf8mb4NoAttributesPayload ) :
502
- ( SupportsQueryAttributes ? s_setNamesUtf8WithAttributesPayload : s_setNamesUtf8NoAttributesPayload ) ;
503
-
504
- // disable pipelining for RDS MySQL 5.7 (assuming Aurora); otherwise take it from the connection string or default to true
505
- if ( ! cs . Pipelining . HasValue && ServerVersion . Version . Major == 5 && ServerVersion . Version . Minor == 7 && HostName . EndsWith ( ".rds.amazonaws.com" , StringComparison . OrdinalIgnoreCase ) )
506
- {
507
- Log . AutoDetectedAurora57 ( m_logger , Id , HostName ) ;
508
- m_supportsPipelining = false ;
509
- }
510
- else
511
- {
512
- // pipelining is not currently compatible with compression
513
- m_supportsPipelining = ! cs . UseCompression && cs . Pipelining is not false ;
476
+ m_supportsConnectionAttributes = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . ConnectionAttributes ) != 0 ;
477
+ m_supportsDeprecateEof = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . DeprecateEof ) != 0 ;
478
+ SupportsCachedPreparedMetadata = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . MariaDbCacheMetadata ) != 0 ;
479
+ SupportsQueryAttributes = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . QueryAttributes ) != 0 ;
480
+ m_supportsSessionTrack = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . SessionTrack ) != 0 ;
481
+ var serverSupportsSsl = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . Ssl ) != 0 ;
482
+ m_characterSet = ServerVersion . Version >= ServerVersions . SupportsUtf8Mb4 ? CharacterSet . Utf8Mb4GeneralCaseInsensitive : CharacterSet . Utf8Mb3GeneralCaseInsensitive ;
483
+ m_setNamesPayload = ServerVersion . Version >= ServerVersions . SupportsUtf8Mb4 ?
484
+ ( SupportsQueryAttributes ? s_setNamesUtf8mb4WithAttributesPayload : s_setNamesUtf8mb4NoAttributesPayload ) :
485
+ ( SupportsQueryAttributes ? s_setNamesUtf8WithAttributesPayload : s_setNamesUtf8NoAttributesPayload ) ;
486
+
487
+ // disable pipelining for RDS MySQL 5.7 (assuming Aurora); otherwise take it from the connection string or default to true
488
+ if ( ! cs . Pipelining . HasValue && ServerVersion . Version . Major == 5 && ServerVersion . Version . Minor == 7 && HostName . EndsWith ( ".rds.amazonaws.com" , StringComparison . OrdinalIgnoreCase ) )
489
+ {
490
+ Log . AutoDetectedAurora57 ( m_logger , Id , HostName ) ;
491
+ m_supportsPipelining = false ;
492
+ }
493
+ else
494
+ {
495
+ // pipelining is not currently compatible with compression
496
+ m_supportsPipelining = ! cs . UseCompression && cs . Pipelining is not false ;
514
497
515
- // for pipelining, concatenate reset connection and SET NAMES query into one buffer
516
- if ( m_supportsPipelining )
517
- {
518
- m_pipelinedResetConnectionBytes = new byte [ m_setNamesPayload . Span . Length + 9 ] ;
498
+ // for pipelining, concatenate reset connection and SET NAMES query into one buffer
499
+ if ( m_supportsPipelining )
500
+ {
501
+ m_pipelinedResetConnectionBytes = new byte [ m_setNamesPayload . Span . Length + 9 ] ;
519
502
520
- // first packet: reset connection
521
- m_pipelinedResetConnectionBytes [ 0 ] = 1 ;
522
- m_pipelinedResetConnectionBytes [ 4 ] = ( byte ) CommandKind . ResetConnection ;
503
+ // first packet: reset connection
504
+ m_pipelinedResetConnectionBytes [ 0 ] = 1 ;
505
+ m_pipelinedResetConnectionBytes [ 4 ] = ( byte ) CommandKind . ResetConnection ;
523
506
524
- // second packet: SET NAMES query
525
- m_pipelinedResetConnectionBytes [ 5 ] = ( byte ) m_setNamesPayload . Span . Length ;
526
- m_setNamesPayload . Span . CopyTo ( m_pipelinedResetConnectionBytes . AsSpan ( ) [ 9 ..] ) ;
527
- }
507
+ // second packet: SET NAMES query
508
+ m_pipelinedResetConnectionBytes [ 5 ] = ( byte ) m_setNamesPayload . Span . Length ;
509
+ m_setNamesPayload . Span . CopyTo ( m_pipelinedResetConnectionBytes . AsSpan ( ) [ 9 ..] ) ;
528
510
}
511
+ }
529
512
530
- Log . SessionMadeConnection ( m_logger , Id , ServerVersion . OriginalString , ConnectionId , m_useCompression , m_supportsConnectionAttributes , m_supportsDeprecateEof , SupportsCachedPreparedMetadata , serverSupportsSsl , m_supportsSessionTrack , m_supportsPipelining , SupportsQueryAttributes ) ;
531
-
532
- if ( cs . SslMode != MySqlSslMode . None && ( cs . SslMode != MySqlSslMode . Preferred || serverSupportsSsl ) )
533
- {
534
- if ( ! serverSupportsSsl )
535
- {
536
- Log . ServerDoesNotSupportSsl ( m_logger , Id ) ;
537
- throw new MySqlException ( MySqlErrorCode . UnableToConnectToHost , "Server does not support SSL" ) ;
538
- }
539
-
540
- try
541
- {
542
- await InitSslAsync ( initialHandshake . ProtocolCapabilities , cs , connection , sslProtocols , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
543
- shouldRetrySsl = false ;
544
- if ( shouldUpdatePoolSslProtocols && Pool is not null )
545
- Pool . SslProtocols = sslProtocols ;
546
- }
547
- catch ( ArgumentException ex ) when ( ex . ParamName == "sslProtocolType" && sslProtocols == SslProtocols . None )
548
- {
549
- Log . SessionDoesNotSupportSslProtocolsNone ( m_logger , ex , Id ) ;
550
- sslProtocols = SslProtocols . Tls | SslProtocols . Tls11 | SslProtocols . Tls12 ;
551
- }
552
- catch ( Exception ex ) when ( shouldRetrySsl && IsRetryableException ( ex ) )
553
- {
554
- // negotiating TLS 1.2 with a yaSSL-based server throws an exception on Windows, see comment at top of method
555
- Log . FailedNegotiatingTls ( m_logger , ex , Id ) ;
556
- sslProtocols = sslProtocols == SslProtocols . None ? SslProtocols . Tls | SslProtocols . Tls11 : ( SslProtocols . Tls | SslProtocols . Tls11 ) & sslProtocols ;
557
- shouldUpdatePoolSslProtocols = true ;
558
- }
513
+ Log . SessionMadeConnection ( m_logger , Id , ServerVersion . OriginalString , ConnectionId , m_useCompression , m_supportsConnectionAttributes , m_supportsDeprecateEof , SupportsCachedPreparedMetadata , serverSupportsSsl , m_supportsSessionTrack , m_supportsPipelining , SupportsQueryAttributes ) ;
559
514
560
- static bool IsRetryableException ( Exception ? ex ) => ( ex is MySqlException && IsRetryableException ( ex . InnerException ) ) ||
561
- ( ex is AuthenticationException or ( IOException and not FileNotFoundException and not DirectoryNotFoundException and not DriveNotFoundException and not PathTooLongException ) ) ;
562
- }
563
- else
515
+ if ( cs . SslMode != MySqlSslMode . None && ( cs . SslMode != MySqlSslMode . Preferred || serverSupportsSsl ) )
516
+ {
517
+ if ( ! serverSupportsSsl )
564
518
{
565
- shouldRetrySsl = false ;
519
+ Log . ServerDoesNotSupportSsl ( m_logger , Id ) ;
520
+ throw new MySqlException ( MySqlErrorCode . UnableToConnectToHost , "Server does not support SSL" ) ;
566
521
}
567
522
568
- if ( shouldRetrySsl )
569
- {
570
- // avoid "The collection already contains item with same key 'net.transport'" exception when retrying SSL
571
- m_activityTags . Remove ( ActivitySourceHelper . NetTransportTagName ) ;
572
- m_activityTags . Remove ( ActivitySourceHelper . NetPeerNameTagName ) ;
573
- m_activityTags . Remove ( ActivitySourceHelper . NetPeerPortTagName ) ;
574
- }
575
- } while ( shouldRetrySsl ) ;
523
+ await InitSslAsync ( initialHandshake . ProtocolCapabilities , cs , connection , cs . TlsVersions , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
524
+ }
576
525
577
526
if ( m_supportsConnectionAttributes && cs . ConnectionAttributes is null )
578
527
cs . ConnectionAttributes = CreateConnectionAttributes ( cs . ApplicationName ) ;
0 commit comments