11using System ;
2+ using System . Diagnostics ;
3+ using System . Globalization ;
24using System . IO ;
35using System . Net ;
46using System . Net . Security ;
57using System . Net . Sockets ;
8+ using System . Reflection ;
9+ using System . Runtime . InteropServices ;
610using System . Security . Authentication ;
711using System . Security . Cryptography ;
812using System . Security . Cryptography . X509Certificates ;
@@ -233,7 +237,11 @@ public async Task ConnectAsync(ConnectionSettings cs, IOBehavior ioBehavior, Can
233237 await InitSslAsync ( initialHandshake . ProtocolCapabilities , cs , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
234238 }
235239
236- var response = HandshakeResponse41Packet . Create ( initialHandshake , cs , m_useCompression ) ;
240+ m_supportsConnectionAttributes = ( initialHandshake . ProtocolCapabilities & ProtocolCapabilities . ConnectionAttributes ) != 0 ;
241+ if ( m_supportsConnectionAttributes && s_connectionAttributes == null )
242+ s_connectionAttributes = CreateConnectionAttributes ( ) ;
243+
244+ var response = HandshakeResponse41Packet . Create ( initialHandshake , cs , m_useCompression , m_supportsConnectionAttributes ? s_connectionAttributes : null ) ;
237245 payload = new PayloadData ( new ArraySegment < byte > ( response ) ) ;
238246 await SendReplyAsync ( payload , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
239247 payload = await ReceiveReplyAsync ( ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
@@ -270,7 +278,7 @@ public async Task ResetConnectionAsync(ConnectionSettings cs, IOBehavior ioBehav
270278 {
271279 // optimistically hash the password with the challenge from the initial handshake (supported by MariaDB; doesn't appear to be supported by MySQL)
272280 var hashedPassword = AuthenticationUtility . CreateAuthenticationResponse ( AuthPluginData , 0 , cs . Password ) ;
273- var payload = ChangeUserPayload . Create ( cs . UserID , hashedPassword , cs . Database ) ;
281+ var payload = ChangeUserPayload . Create ( cs . UserID , hashedPassword , cs . Database , m_supportsConnectionAttributes ? s_connectionAttributes : null ) ;
274282 await SendAsync ( payload , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
275283 payload = await ReceiveReplyAsync ( ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
276284 if ( payload . HeaderByte == AuthenticationMethodSwitchRequestPayload . Signature )
@@ -768,6 +776,46 @@ private void VerifyState(State state1, State state2)
768776 throw new InvalidOperationException ( "Expected state to be ({0}|{1}) but was {2}." . FormatInvariant ( state1 , state2 , m_state ) ) ;
769777 }
770778
779+ private static byte [ ] CreateConnectionAttributes ( )
780+ {
781+ var attributesWriter = new PayloadWriter ( ) ;
782+ attributesWriter . WriteLengthEncodedString ( "_client_name" ) ;
783+ attributesWriter . WriteLengthEncodedString ( "MySqlConnector" ) ;
784+ attributesWriter . WriteLengthEncodedString ( "_client_version" ) ;
785+ attributesWriter . WriteLengthEncodedString ( typeof ( MySqlSession ) . GetTypeInfo ( ) . Assembly . GetCustomAttribute < AssemblyInformationalVersionAttribute > ( ) . InformationalVersion ) ;
786+ try
787+ {
788+ var os = RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ? "Windows" :
789+ RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ? "Linux" :
790+ RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ? "macOS" : null ;
791+ var osDetails = RuntimeInformation . OSDescription ;
792+ var platform = RuntimeInformation . ProcessArchitecture . ToString ( ) ;
793+ if ( os != null )
794+ {
795+ attributesWriter . WriteLengthEncodedString ( "_os" ) ;
796+ attributesWriter . WriteLengthEncodedString ( os ) ;
797+ }
798+ attributesWriter . WriteLengthEncodedString ( "_os_details" ) ;
799+ attributesWriter . WriteLengthEncodedString ( osDetails ) ;
800+ attributesWriter . WriteLengthEncodedString ( "_platform" ) ;
801+ attributesWriter . WriteLengthEncodedString ( platform ) ;
802+ }
803+ catch ( PlatformNotSupportedException )
804+ {
805+ }
806+ using ( var process = Process . GetCurrentProcess ( ) )
807+ {
808+ attributesWriter . WriteLengthEncodedString ( "_pid" ) ;
809+ attributesWriter . WriteLengthEncodedString ( process . Id . ToString ( CultureInfo . InvariantCulture ) ) ;
810+ }
811+ var connectionAttributes = attributesWriter . ToBytes ( ) ;
812+
813+ var writer = new PayloadWriter ( ) ;
814+ writer . WriteLengthEncodedInteger ( ( ulong ) connectionAttributes . Length ) ;
815+ writer . Write ( connectionAttributes ) ;
816+ return writer . ToBytes ( ) ;
817+ }
818+
771819 private enum State
772820 {
773821 // The session has been created; no connection has been made.
@@ -798,6 +846,8 @@ private enum State
798846 Failed ,
799847 }
800848
849+ static byte [ ] s_connectionAttributes ;
850+
801851 readonly object m_lock ;
802852 readonly ArraySegmentHolder < byte > m_payloadCache ;
803853 State m_state ;
@@ -814,5 +864,6 @@ private enum State
814864 MySqlDataReader m_activeReader ;
815865 bool m_useCompression ;
816866 bool m_isSecureConnection ;
867+ bool m_supportsConnectionAttributes ;
817868 }
818869}
0 commit comments