Skip to content

Commit bfc6c47

Browse files
committed
CSHARP-1730: Implement the client handshake protocol.
1 parent 40be77e commit bfc6c47

22 files changed

+516
-34
lines changed

src/MongoDB.Driver.Core/Core/Configuration/ClusterBuilderExtensions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,10 @@ public static ClusterBuilder ConfigureWithConnectionString(this ClusterBuilder b
105105
var authenticator = CreateAuthenticator(connectionString);
106106
builder = builder.ConfigureConnection(s => s.With(authenticators: new[] { authenticator }));
107107
}
108-
108+
if (connectionString.ApplicationName != null)
109+
{
110+
builder = builder.ConfigureConnection(s => s.With(applicationName: connectionString.ApplicationName));
111+
}
109112
if (connectionString.MaxIdleTime != null)
110113
{
111114
builder = builder.ConfigureConnection(s => s.With(maxIdleTime: connectionString.MaxIdleTime.Value));

src/MongoDB.Driver.Core/Core/Configuration/ConnectionSettings.cs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2013-2015 MongoDB Inc.
1+
/* Copyright 2013-2016 MongoDB Inc.
22
*
33
* Licensed under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License.
@@ -32,28 +32,43 @@ public class ConnectionSettings
3232
#endregion
3333

3434
// fields
35+
private readonly string _applicationName;
3536
private readonly IReadOnlyList<IAuthenticator> _authenticators;
3637
private readonly TimeSpan _maxIdleTime;
3738
private readonly TimeSpan _maxLifeTime;
3839

3940
// constructors
4041
/// <summary>
41-
/// Initializes a new instance of the <see cref="ConnectionSettings"/> class.
42+
/// Initializes a new instance of the <see cref="ConnectionSettings" /> class.
4243
/// </summary>
4344
/// <param name="authenticators">The authenticators.</param>
4445
/// <param name="maxIdleTime">The maximum idle time.</param>
4546
/// <param name="maxLifeTime">The maximum life time.</param>
47+
/// <param name="applicationName">The application name.</param>
4648
public ConnectionSettings(
4749
Optional<IEnumerable<IAuthenticator>> authenticators = default(Optional<IEnumerable<IAuthenticator>>),
4850
Optional<TimeSpan> maxIdleTime = default(Optional<TimeSpan>),
49-
Optional<TimeSpan> maxLifeTime = default(Optional<TimeSpan>))
51+
Optional<TimeSpan> maxLifeTime = default(Optional<TimeSpan>),
52+
Optional<string> applicationName = default(Optional<string>))
5053
{
5154
_authenticators = Ensure.IsNotNull(authenticators.WithDefault(__noAuthenticators), "authenticators").ToList();
5255
_maxIdleTime = Ensure.IsGreaterThanZero(maxIdleTime.WithDefault(TimeSpan.FromMinutes(10)), "maxIdleTime");
5356
_maxLifeTime = Ensure.IsGreaterThanZero(maxLifeTime.WithDefault(TimeSpan.FromMinutes(30)), "maxLifeTime");
57+
_applicationName = applicationName.WithDefault(null);
5458
}
5559

5660
// properties
61+
/// <summary>
62+
/// Gets the name of the application.
63+
/// </summary>
64+
/// <value>
65+
/// The name of the application.
66+
/// </value>
67+
public string ApplicationName
68+
{
69+
get { return _applicationName; }
70+
}
71+
5772
/// <summary>
5873
/// Gets the authenticators.
5974
/// </summary>
@@ -94,16 +109,19 @@ public TimeSpan MaxLifeTime
94109
/// <param name="authenticators">The authenticators.</param>
95110
/// <param name="maxIdleTime">The maximum idle time.</param>
96111
/// <param name="maxLifeTime">The maximum life time.</param>
112+
/// <param name="applicationName">The application name.</param>
97113
/// <returns>A new ConnectionSettings instance.</returns>
98114
public ConnectionSettings With(
99115
Optional<IEnumerable<IAuthenticator>> authenticators = default(Optional<IEnumerable<IAuthenticator>>),
100116
Optional<TimeSpan> maxIdleTime = default(Optional<TimeSpan>),
101-
Optional<TimeSpan> maxLifeTime = default(Optional<TimeSpan>))
117+
Optional<TimeSpan> maxLifeTime = default(Optional<TimeSpan>),
118+
Optional<string> applicationName = default(Optional<string>))
102119
{
103120
return new ConnectionSettings(
104121
authenticators: Optional.Enumerable(authenticators.WithDefault(_authenticators)),
105122
maxIdleTime: maxIdleTime.WithDefault(_maxIdleTime),
106-
maxLifeTime: maxLifeTime.WithDefault(_maxLifeTime));
123+
maxLifeTime: maxLifeTime.WithDefault(_maxLifeTime),
124+
applicationName: applicationName.WithDefault(_applicationName));
107125
}
108126
}
109127
}

src/MongoDB.Driver.Core/Core/Configuration/ConnectionString.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public sealed class ConnectionString
4141

4242
// these are all readonly, but since they are not assigned
4343
// from the ctor, they cannot be marked as such.
44+
private string _applicationName;
4445
private string _authMechanism;
4546
private string _authSource;
4647
private ClusterConnectionMode _connect;
@@ -107,6 +108,14 @@ public IEnumerable<string> AllUnknownOptionNames
107108
get { return _unknownOptions.AllKeys; }
108109
}
109110

111+
/// <summary>
112+
/// Gets the application name.
113+
/// </summary>
114+
public string ApplicationName
115+
{
116+
get { return _applicationName; }
117+
}
118+
110119
/// <summary>
111120
/// Gets the auth mechanism.
112121
/// </summary>
@@ -482,6 +491,9 @@ private void ParseOption(string name, string value)
482491
{
483492
switch (name.ToLower())
484493
{
494+
case "appname":
495+
_applicationName = value;
496+
break;
485497
case "authmechanism":
486498
_authMechanism = value;
487499
break;

src/MongoDB.Driver.Core/Core/Connections/BinaryConnectionFactory.cs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2013-2015 MongoDB Inc.
1+
/* Copyright 2013-2016 MongoDB Inc.
22
*
33
* Licensed under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License.
@@ -26,18 +26,8 @@ namespace MongoDB.Driver.Core.Connections
2626
/// </summary>
2727
internal class BinaryConnectionFactory : IConnectionFactory
2828
{
29-
#region static
30-
// static fields
31-
private static readonly IConnectionInitializer __connectionInitializer;
32-
33-
// static constructor
34-
static BinaryConnectionFactory()
35-
{
36-
__connectionInitializer = new ConnectionInitializer();
37-
}
38-
#endregion
39-
4029
// fields
30+
private readonly IConnectionInitializer _connectionInitializer;
4131
private readonly IEventSubscriber _eventSubscriber;
4232
private readonly ConnectionSettings _settings;
4333
private readonly IStreamFactory _streamFactory;
@@ -48,14 +38,15 @@ public BinaryConnectionFactory(ConnectionSettings settings, IStreamFactory strea
4838
_settings = Ensure.IsNotNull(settings, nameof(settings));
4939
_streamFactory = Ensure.IsNotNull(streamFactory, nameof(streamFactory));
5040
_eventSubscriber = Ensure.IsNotNull(eventSubscriber, nameof(eventSubscriber));
41+
_connectionInitializer = new ConnectionInitializer(settings.ApplicationName);
5142
}
5243

5344
// methods
5445
public IConnection CreateConnection(ServerId serverId, EndPoint endPoint)
5546
{
5647
Ensure.IsNotNull(serverId, nameof(serverId));
5748
Ensure.IsNotNull(endPoint, nameof(endPoint));
58-
return new BinaryConnection(serverId, endPoint, _settings, _streamFactory, __connectionInitializer, _eventSubscriber);
49+
return new BinaryConnection(serverId, endPoint, _settings, _streamFactory, _connectionInitializer, _eventSubscriber);
5950
}
6051
}
6152
}

src/MongoDB.Driver.Core/Core/Connections/ConnectionInitializer.cs

Lines changed: 130 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2013-2015 MongoDB Inc.
1+
/* Copyright 2013-2016 MongoDB Inc.
22
*
33
* Licensed under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License.
@@ -14,6 +14,9 @@
1414
*/
1515

1616
using System;
17+
using System.Reflection;
18+
using System.Runtime.InteropServices;
19+
using System.Text.RegularExpressions;
1720
using System.Threading;
1821
using System.Threading.Tasks;
1922
using MongoDB.Bson;
@@ -29,6 +32,101 @@ namespace MongoDB.Driver.Core.Connections
2932
/// </summary>
3033
internal class ConnectionInitializer : IConnectionInitializer
3134
{
35+
#region static
36+
// private static fields
37+
private static readonly Lazy<BsonDocument> __driverDocument = new Lazy<BsonDocument>(CreateDriverDocument);
38+
private static readonly Lazy<BsonDocument> __osDocument = new Lazy<BsonDocument>(CreateOSDocument);
39+
private static readonly Lazy<string> __platformString = new Lazy<string>(GetPlatformString);
40+
41+
// private static methods
42+
internal static BsonDocument CreateDriverDocument()
43+
{
44+
var assembly = typeof(ConnectionInitializer).GetTypeInfo().Assembly;
45+
var fileVersionAttribute = assembly.GetCustomAttribute<AssemblyFileVersionAttribute>();
46+
var driverVersion = fileVersionAttribute.Version;
47+
48+
return CreateDriverDocument(driverVersion);
49+
}
50+
51+
internal static BsonDocument CreateDriverDocument(string driverVersion)
52+
{
53+
return new BsonDocument
54+
{
55+
{ "name", "dotnet" },
56+
{ "version", driverVersion }
57+
};
58+
}
59+
60+
internal static BsonDocument CreateOSDocument()
61+
{
62+
string osType;
63+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
64+
{
65+
osType = "Windows";
66+
}
67+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
68+
{
69+
osType = "Linux";
70+
}
71+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
72+
{
73+
osType = "macOS";
74+
}
75+
else
76+
{
77+
osType = "unknown";
78+
}
79+
80+
var osName = RuntimeInformation.OSDescription.Trim();
81+
82+
string architecture;
83+
switch (RuntimeInformation.ProcessArchitecture)
84+
{
85+
case Architecture.Arm: architecture = "arm"; break;
86+
case Architecture.Arm64: architecture = "arm64"; break;
87+
case Architecture.X64: architecture = "x86_64"; break;
88+
case Architecture.X86: architecture = "x86_32"; break;
89+
default: architecture = null; break;
90+
}
91+
92+
string osVersion;
93+
var match = Regex.Match(osName, @" (?<version>\d+\.\d[^ ]*)");
94+
if (match.Success)
95+
{
96+
osVersion = match.Groups["version"].Value;
97+
}
98+
else
99+
{
100+
osVersion = null;
101+
}
102+
103+
return CreateOSDocument(osType, osName, architecture, osVersion);
104+
}
105+
106+
internal static BsonDocument CreateOSDocument(string osType, string osName, string architecture, string osVersion)
107+
{
108+
return new BsonDocument
109+
{
110+
{ "type", osType },
111+
{ "name", osName },
112+
{ "architecture", architecture, architecture != null },
113+
{ "version", osVersion, osVersion != null }
114+
};
115+
}
116+
117+
internal static string GetPlatformString()
118+
{
119+
return RuntimeInformation.FrameworkDescription;
120+
}
121+
#endregion
122+
123+
private readonly BsonDocument _clientDocument;
124+
125+
public ConnectionInitializer(string applicationName)
126+
{
127+
_clientDocument = CreateClientDocument(applicationName);
128+
}
129+
32130
public ConnectionDescription InitializeConnection(IConnection connection, CancellationToken cancellationToken)
33131
{
34132
Ensure.IsNotNull(connection, nameof(connection));
@@ -100,6 +198,22 @@ private CommandWireProtocol<BsonDocument> CreateBuildInfoProtocol()
100198
return buildInfoProtocol;
101199
}
102200

201+
internal BsonDocument CreateClientDocument(string applicationName)
202+
{
203+
return CreateClientDocument(applicationName, __driverDocument.Value, __osDocument.Value, __platformString.Value);
204+
}
205+
206+
internal BsonDocument CreateClientDocument(string applicationName, BsonDocument driverDocument, BsonDocument osDocument, string platformString)
207+
{
208+
return new BsonDocument
209+
{
210+
{ "application", () => new BsonDocument("name", applicationName), applicationName != null },
211+
{ "driver", driverDocument },
212+
{ "os", osDocument },
213+
{ "platform", platformString }
214+
};
215+
}
216+
103217
private CommandWireProtocol<BsonDocument> CreateGetLastErrorProtocol()
104218
{
105219
var getLastErrorCommand = new BsonDocument("getLastError", 1);
@@ -112,9 +226,23 @@ private CommandWireProtocol<BsonDocument> CreateGetLastErrorProtocol()
112226
return getLastErrorProtocol;
113227
}
114228

229+
internal BsonDocument CreateIsMasterCommand()
230+
{
231+
return CreateIsMasterCommand(_clientDocument);
232+
}
233+
234+
internal BsonDocument CreateIsMasterCommand(BsonDocument clientDocument)
235+
{
236+
return new BsonDocument
237+
{
238+
{ "isMaster", 1 },
239+
{ "client", clientDocument }
240+
};
241+
}
242+
115243
private CommandWireProtocol<BsonDocument> CreateIsMasterProtocol()
116244
{
117-
var isMasterCommand = new BsonDocument("isMaster", 1);
245+
var isMasterCommand = CreateIsMasterCommand();
118246
var isMasterProtocol = new CommandWireProtocol<BsonDocument>(
119247
DatabaseNamespace.Admin,
120248
isMasterCommand,

src/MongoDB.Driver.Core/MongoDB.Driver.Core.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
<ItemGroup>
3737
<Reference Include="System" />
3838
<Reference Include="System.Core" />
39+
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
40+
<HintPath>..\..\packages\System.Runtime.InteropServices.RuntimeInformation.4.0.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
41+
<Private>True</Private>
42+
</Reference>
3943
</ItemGroup>
4044
<ItemGroup>
4145
<Compile Include="..\MongoDB.Shared\GlobalAssemblyInfo.cs">
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<packages>
33
<package id="AsyncUsageAnalyzers" version="1.0.0-alpha003" targetFramework="net45" developmentDependency="true" />
4+
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.0.0" targetFramework="net45" />
45
</packages>

0 commit comments

Comments
 (0)