1
1
using System ;
2
+ using System . Diagnostics ;
3
+ using System . Globalization ;
2
4
using System . IO ;
3
5
using System . Net ;
4
6
using System . Net . Security ;
5
7
using System . Net . Sockets ;
8
+ using System . Reflection ;
9
+ using System . Runtime . InteropServices ;
6
10
using System . Security . Authentication ;
7
11
using System . Security . Cryptography ;
8
12
using System . Security . Cryptography . X509Certificates ;
@@ -233,7 +237,11 @@ public async Task ConnectAsync(ConnectionSettings cs, IOBehavior ioBehavior, Can
233
237
await InitSslAsync ( initialHandshake . ProtocolCapabilities , cs , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
234
238
}
235
239
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 ) ;
237
245
payload = new PayloadData ( new ArraySegment < byte > ( response ) ) ;
238
246
await SendReplyAsync ( payload , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
239
247
payload = await ReceiveReplyAsync ( ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
@@ -270,7 +278,7 @@ public async Task ResetConnectionAsync(ConnectionSettings cs, IOBehavior ioBehav
270
278
{
271
279
// optimistically hash the password with the challenge from the initial handshake (supported by MariaDB; doesn't appear to be supported by MySQL)
272
280
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 ) ;
274
282
await SendAsync ( payload , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
275
283
payload = await ReceiveReplyAsync ( ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
276
284
if ( payload . HeaderByte == AuthenticationMethodSwitchRequestPayload . Signature )
@@ -768,6 +776,46 @@ private void VerifyState(State state1, State state2)
768
776
throw new InvalidOperationException ( "Expected state to be ({0}|{1}) but was {2}." . FormatInvariant ( state1 , state2 , m_state ) ) ;
769
777
}
770
778
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
+
771
819
private enum State
772
820
{
773
821
// The session has been created; no connection has been made.
@@ -798,6 +846,8 @@ private enum State
798
846
Failed ,
799
847
}
800
848
849
+ static byte [ ] s_connectionAttributes ;
850
+
801
851
readonly object m_lock ;
802
852
readonly ArraySegmentHolder < byte > m_payloadCache ;
803
853
State m_state ;
@@ -814,5 +864,6 @@ private enum State
814
864
MySqlDataReader m_activeReader ;
815
865
bool m_useCompression ;
816
866
bool m_isSecureConnection ;
867
+ bool m_supportsConnectionAttributes ;
817
868
}
818
869
}
0 commit comments