Skip to content

Commit abbbafe

Browse files
committed
add protocol version check
1 parent 34d0639 commit abbbafe

File tree

10 files changed

+168
-74
lines changed

10 files changed

+168
-74
lines changed

ConnectX.Client/Client.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ private async Task<OpResult> PerformOpAndGetRoomInfoAsync<T>(T message, Cancella
159159
if (opResult.Status != GroupCreationStatus.Succeeded)
160160
return new OpResult(null, opResult.Status, ReadOnlyDictionary<string, string>.Empty, opResult.ErrorMessage);
161161

162-
if (opResult.Metadata.TryGetValue(GroupOpResult.UseRelayServerKey, out var useRelayServerStr) &&
162+
if (opResult.Metadata.TryGetValue(GroupOpResult.MetadataUseRelayServer, out var useRelayServerStr) &&
163163
bool.TryParse(useRelayServerStr, out var useRelayServer) &&
164164
!useRelayServer)
165165
{

ConnectX.Client/Interfaces/IServerLinkHolder.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Hive.Network.Abstractions.Session;
1+
using ConnectX.Shared.Messages.Identity;
2+
using Hive.Network.Abstractions.Session;
23
using Microsoft.Extensions.Hosting;
34

45
namespace ConnectX.Client.Interfaces;
@@ -12,6 +13,6 @@ public interface IServerLinkHolder : IHostedService
1213

1314
event Action OnServerLinkDisconnected;
1415

15-
Task ConnectAsync(CancellationToken cancellationToken);
16+
Task<SigninResult?> ConnectAsync(CancellationToken cancellationToken);
1617
Task DisconnectAsync(CancellationToken cancellationToken);
1718
}

ConnectX.Client/ServerLinkHolder.cs

Lines changed: 51 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Net;
22
using ConnectX.Client.Interfaces;
3+
using ConnectX.Shared;
34
using ConnectX.Shared.Helpers;
45
using ConnectX.Shared.Messages;
56
using ConnectX.Shared.Messages.Identity;
@@ -83,48 +84,63 @@ private async Task CheckServerLivenessAsync(CancellationToken cancellationToken)
8384
}
8485
}
8586

86-
public async Task ConnectAsync(CancellationToken cancellationToken)
87+
public async Task<SigninResult?> ConnectAsync(CancellationToken cancellationToken)
8788
{
88-
_dispatcher.AddHandler<SigninSucceeded>(OnSigninSucceededReceived);
89-
9089
_logger.LogConnectingToServer();
9190

92-
try
93-
{
94-
var endPoint = new IPEndPoint(_settingProvider.ServerAddress, _settingProvider.ServerPort);
95-
var session = await _tcpConnector.ConnectAsync(endPoint, cancellationToken);
96-
97-
if (session == null)
98-
{
99-
_logger.LogFailedToConnectToServer(endPoint);
100-
return;
101-
}
91+
var endPoint = new IPEndPoint(_settingProvider.ServerAddress, _settingProvider.ServerPort);
92+
var session = await _tcpConnector.ConnectAsync(endPoint, cancellationToken);
10293

103-
session.BindTo(_dispatcher);
104-
session.StartAsync(cancellationToken).Forget();
94+
if (session == null)
95+
{
96+
_logger.LogFailedToConnectToServer(endPoint);
97+
return null;
98+
}
10599

106-
_logger.LogSendingSigninMessageToServer();
100+
session.BindTo(_dispatcher);
101+
session.StartAsync(cancellationToken).Forget();
107102

108-
await Task.Delay(1000, cancellationToken);
109-
await _dispatcher.SendAsync(session, new SigninMessage
110-
{
111-
JoinP2PNetwork = _settingProvider.JoinP2PNetwork,
112-
DisplayName = $"User-{Guid.CreateVersion7().ToString("N")[^6..]}"
113-
}, cancellationToken);
103+
_logger.LogSendingSigninMessageToServer();
114104

115-
await TaskHelper.WaitUntilAsync(() => IsSignedIn, cancellationToken);
105+
await Task.Delay(1000, cancellationToken);
116106

117-
_logger.LogConnectedAndSignedToServer(endPoint);
107+
var signin = new SigninMessage
108+
{
109+
JoinP2PNetwork = _settingProvider.JoinP2PNetwork,
110+
DisplayName = $"User-{Guid.CreateVersion7().ToString("N")[^6..]}",
111+
LinkProtocolMajor = LinkProtocolConstants.ProtocolMajor,
112+
LinkProtocolMinor = LinkProtocolConstants.ProtocolMinor
113+
};
118114

119-
ServerSession = session;
120-
IsConnected = true;
115+
var result = await _dispatcher.SendAndListenOnce<SigninMessage, SigninResult>(session, signin, cancellationToken);
121116

122-
Hive.Common.Shared.Helpers.TaskHelper.FireAndForget(() => CheckServerLivenessAsync(cancellationToken));
117+
if (result == null)
118+
{
119+
_logger.LogWaitForSigninResultFailed(endPoint);
120+
return null;
123121
}
124-
finally
122+
123+
if (!result.Succeeded)
125124
{
126-
_dispatcher.RemoveHandler<SigninSucceeded>(OnSigninSucceededReceived);
125+
_logger.LogServerRefusedClientToLogin(endPoint);
126+
return result;
127127
}
128+
129+
_logger.LogSuccessfullyLoggedIn(UserId);
130+
131+
IsSignedIn = result.Succeeded;
132+
UserId = result.UserId;
133+
134+
await TaskHelper.WaitUntilAsync(() => IsSignedIn, cancellationToken);
135+
136+
_logger.LogConnectedAndSignedToServer(endPoint);
137+
138+
ServerSession = session;
139+
IsConnected = true;
140+
141+
Hive.Common.Shared.Helpers.TaskHelper.FireAndForget(() => CheckServerLivenessAsync(cancellationToken));
142+
143+
return result;
128144
}
129145

130146
public async Task DisconnectAsync(CancellationToken cancellationToken)
@@ -142,14 +158,6 @@ public async Task DisconnectAsync(CancellationToken cancellationToken)
142158
IsConnected = false;
143159
}
144160

145-
private void OnSigninSucceededReceived(MessageContext<SigninSucceeded> obj)
146-
{
147-
IsSignedIn = true;
148-
UserId = obj.Message.UserId;
149-
150-
_logger.LogSuccessfullyLoggedIn(UserId);
151-
}
152-
153161
private void OnHeartBeatReceived(MessageContext<HeartBeat> ctx)
154162
{
155163
_lastHeartBeatTime = DateTime.UtcNow;
@@ -228,4 +236,10 @@ internal static partial class ServerLinkHolderLoggers
228236

229237
[LoggerMessage(LogLevel.Critical, "[CLIENT] Link with server [{relayEndPoint}] is down, last heartbeat received [{seconds} seconds ago]")]
230238
public static partial void LogMainServerHeartbeatTimeout(this ILogger logger, IPEndPoint relayEndPoint, double seconds);
239+
240+
[LoggerMessage(LogLevel.Error, "[CLIENT] Wait for signin result failed, endpoint: {endPoint}")]
241+
public static partial void LogWaitForSigninResultFailed(this ILogger logger, IPEndPoint endPoint);
242+
243+
[LoggerMessage(LogLevel.Error, "[CLIENT] Server refused client to login at endpoint {endPoint}")]
244+
public static partial void LogServerRefusedClientToLogin(this ILogger logger, IPEndPoint endPoint);
231245
}

ConnectX.Relay/ServerLinkHolder.cs

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
using ConnectX.Relay.Interfaces;
2-
using ConnectX.Shared.Messages.Identity;
1+
using ConnectX.Relay.Helpers;
2+
using ConnectX.Relay.Interfaces;
3+
using ConnectX.Shared;
4+
using ConnectX.Shared.Helpers;
35
using ConnectX.Shared.Messages;
6+
using ConnectX.Shared.Messages.Identity;
7+
using ConnectX.Shared.Messages.Relay;
48
using Hive.Both.General.Dispatchers;
59
using Hive.Network.Abstractions.Session;
610
using Hive.Network.Tcp;
711
using Microsoft.Extensions.Hosting;
812
using Microsoft.Extensions.Logging;
9-
using ConnectX.Shared.Helpers;
1013
using System.Net;
11-
using ConnectX.Relay.Helpers;
12-
using ConnectX.Shared.Messages.Relay;
1314

1415
namespace ConnectX.Relay;
1516

@@ -36,7 +37,6 @@ public ServerLinkHolder(
3637
_applicationLifetime = applicationLifetime;
3738
_logger = logger;
3839

39-
_dispatcher.AddHandler<SigninSucceeded>(OnSigninSucceededReceived);
4040
_dispatcher.AddHandler<HeartBeat>(OnHeartBeatReceived);
4141
_dispatcher.AddHandler<ShutdownMessage>(OnShutdownMessageReceived);
4242
}
@@ -96,13 +96,30 @@ public async Task ConnectAsync(CancellationToken cancellationToken)
9696
_logger.LogSendingSigninMessageToServer();
9797

9898
await Task.Delay(1000, cancellationToken);
99-
await _dispatcher.SendAsync(session, new SigninMessage
99+
100+
var signin = new SigninMessage
100101
{
101102
JoinP2PNetwork = _settingProvider.JoinP2PNetwork,
102-
DisplayName = session.RemoteEndPoint?.ToString() ?? Guid.CreateVersion7().ToString("N")
103-
}, cancellationToken);
103+
DisplayName = session.RemoteEndPoint?.ToString() ?? Guid.CreateVersion7().ToString("N"),
104+
LinkProtocolMajor = LinkProtocolConstants.ProtocolMajor,
105+
LinkProtocolMinor = LinkProtocolConstants.ProtocolMinor
106+
};
107+
108+
var result = await _dispatcher.SendAndListenOnce<SigninMessage, SigninResult>(session, signin, cancellationToken);
109+
110+
if (result == null)
111+
{
112+
_logger.LogWaitForSigninResultFailed(endPoint);
113+
return;
114+
}
115+
116+
if (!result.Succeeded)
117+
{
118+
_logger.LogServerRefusedClientToLogin(endPoint, result);
119+
return;
120+
}
104121

105-
await TaskHelper.WaitUntilAsync(() => IsSignedIn, cancellationToken);
122+
IsSignedIn = result.Succeeded;
106123

107124
_logger.LogConnectedAndSignedToServer(endPoint);
108125

@@ -153,13 +170,6 @@ public async Task DisconnectAsync(CancellationToken cancellationToken)
153170
IsConnected = false;
154171
}
155172

156-
private void OnSigninSucceededReceived(MessageContext<SigninSucceeded> obj)
157-
{
158-
IsSignedIn = true;
159-
160-
_dispatcher.RemoveHandler<SigninSucceeded>(OnSigninSucceededReceived);
161-
}
162-
163173
private void OnHeartBeatReceived(MessageContext<HeartBeat> ctx)
164174
{
165175
_lastHeartBeatTime = DateTime.UtcNow;
@@ -290,4 +300,10 @@ internal static partial class ServerLinkHolderLoggers
290300

291301
[LoggerMessage(LogLevel.Critical, "[CLIENT] Link with server [{relayEndPoint}] is down, last heartbeat received [{seconds} seconds ago]")]
292302
public static partial void LogMainServerHeartbeatTimeout(this ILogger logger, IPEndPoint relayEndPoint, double seconds);
303+
304+
[LoggerMessage(LogLevel.Information, "[CLIENT] Wait for signin result failed at endpoint {endPoint}")]
305+
public static partial void LogWaitForSigninResultFailed(this ILogger logger, IPEndPoint endPoint);
306+
307+
[LoggerMessage(LogLevel.Information, "[CLIENT] Server refused client to login at endpoint {endPoint}, {signinResult}")]
308+
public static partial void LogServerRefusedClientToLogin(this ILogger logger, IPEndPoint endPoint, SigninResult signinResult);
293309
}

ConnectX.Server/Managers/GroupManager.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ private async Task CreateRoomAsync(Guid userId, MessageContext<CreateGroup> ctx)
458458

459459
var metadata = new Dictionary<string, string>(1)
460460
{
461-
{GroupOpResult.UseRelayServerKey, (assignedRelayServerAddress != null).ToString()}
461+
{GroupOpResult.MetadataUseRelayServer, (assignedRelayServerAddress != null).ToString()}
462462
};
463463

464464
var success = new GroupOpResult(
@@ -505,7 +505,7 @@ private async Task TryGetRoomInfoFromRemoteServerAsync(MessageContext<JoinGroup>
505505
InterconnectServerRegistrationContexts.Default.InterconnectServerRegistration);
506506
var metadata = new Dictionary<string, string>(1)
507507
{
508-
{GroupOpResult.RedirectInfoKey, infoJson}
508+
{GroupOpResult.MetadataRedirectInfo, infoJson}
509509
};
510510
var redirectMsg = new GroupOpResult(
511511
GroupCreationStatus.NeedRedirect,
@@ -592,7 +592,7 @@ private void OnJoinGroupReceived(MessageContext<JoinGroup> ctx)
592592

593593
var metadata = new Dictionary<string, string>(1)
594594
{
595-
{GroupOpResult.UseRelayServerKey, (assignedRelayServerAddress != null).ToString()}
595+
{GroupOpResult.MetadataUseRelayServer, (assignedRelayServerAddress != null).ToString()}
596596
};
597597

598598
var success = new GroupOpResult(

ConnectX.Server/Server.cs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using ConnectX.Server.Interfaces;
44
using ConnectX.Server.Managers;
55
using ConnectX.Server.Messages;
6+
using ConnectX.Shared;
67
using ConnectX.Shared.Helpers;
78
using ConnectX.Shared.Messages;
89
using ConnectX.Shared.Messages.Identity;
@@ -150,6 +151,20 @@ private void OnInterconnectServerRegistrationReceived(MessageContext<Interconnec
150151
_interconnectServerManager.AttachSession(session.Id, session, ctx.Message);
151152
}
152153

154+
private static bool CheckProtocolCompatibility(
155+
int protocolMajor,
156+
int protocolMinor)
157+
{
158+
if (protocolMajor != LinkProtocolConstants.ProtocolMajor)
159+
return false;
160+
if (protocolMinor > LinkProtocolConstants.ProtocolMinor)
161+
return false;
162+
if (protocolMinor < LinkProtocolConstants.ProtocolMinor - LinkProtocolConstants.MaxAllowedMinorShiftCount)
163+
return false;
164+
165+
return true;
166+
}
167+
153168
private void OnSigninMessageReceived(MessageContext<SigninMessage> ctx)
154169
{
155170
var session = ctx.FromSession;
@@ -158,6 +173,34 @@ private void OnSigninMessageReceived(MessageContext<SigninMessage> ctx)
158173
if (!_tempSessionMapping.TryRemove(session.Id, out _))
159174
return;
160175

176+
if (!CheckProtocolCompatibility(ctx.Message.LinkProtocolMajor, ctx.Message.LinkProtocolMinor))
177+
{
178+
var metadata = new Dictionary<string, string>(2)
179+
{
180+
{SigninResult.MetadataServerProtocolMajor, LinkProtocolConstants.ProtocolMajor.ToString("D")},
181+
{SigninResult.MetadataServerProtocolMinor, LinkProtocolConstants.ProtocolMinor.ToString("D")}
182+
};
183+
var result = new SigninResult(
184+
false,
185+
Guid.Empty,
186+
SigninResult.ErrorProtocolMismatch,
187+
metadata);
188+
189+
_dispatcher
190+
.SendAsync(session, result)
191+
.AsTask()
192+
.ContinueWith(_ => session.Close())
193+
.Forget();
194+
195+
_logger.LogSessionProtocolMismatch(
196+
session.RemoteEndPoint!,
197+
session.Id,
198+
ctx.Message.LinkProtocolMajor,
199+
ctx.Message.LinkProtocolMinor);
200+
201+
return;
202+
}
203+
161204
var newVal = Interlocked.Increment(ref _currentSessionCount);
162205
_logger.LogCurrentOnline(newVal);
163206

@@ -167,7 +210,7 @@ private void OnSigninMessageReceived(MessageContext<SigninMessage> ctx)
167210

168211
var userId = _groupManager.AttachSession(session.Id, session, ctx.Message);
169212

170-
_dispatcher.SendAsync(session, new SigninSucceeded(userId)).Forget();
213+
_dispatcher.SendAsync(session, new SigninResult(true, userId)).Forget();
171214

172215
_relayServerManager.AttachSession(session.Id, userId, session);
173216
_p2pManager.AttachSession(session, userId, ctx.Message);
@@ -206,4 +249,7 @@ internal static partial class ServerLoggers
206249

207250
[LoggerMessage(LogLevel.Information, "Server stopped.")]
208251
public static partial void LogServerStopped(this ILogger logger);
252+
253+
[LoggerMessage(LogLevel.Warning, "[CLIENT] Session protocol mismatch, EndPoint [{endPoint}] ID [{id}], Version [{protocolMajor}.{protocolMinor}], disconnecting from the server...")]
254+
public static partial void LogSessionProtocolMismatch(this ILogger logger, IPEndPoint endPoint, SessionId id, int protocolMajor, int protocolMinor);
209255
}

ConnectX.Shared/Messages/Group/GroupOpResult.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ public partial class GroupOpResult(
1111
string? errorMessage = null,
1212
IReadOnlyDictionary<string, string>? metadata = null)
1313
{
14-
public const string RedirectInfoKey = "RedirectInfo";
15-
public const string UseRelayServerKey = "UseRelayServer";
14+
public const string MetadataRedirectInfo = "RedirectInfo";
15+
public const string MetadataUseRelayServer = "UseRelayServer";
1616

1717
public string? ErrorMessage { get; } = errorMessage;
1818
public Guid RoomId { get; init; }

ConnectX.Shared/Messages/Identity/SigninMessage.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,8 @@ public partial class SigninMessage
1010
public required string DisplayName { get; init; }
1111

1212
public required bool JoinP2PNetwork { get; init; }
13+
14+
public required int LinkProtocolMajor { get; init; }
15+
16+
public required int LinkProtocolMinor { get; init; }
1317
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using Hive.Codec.Shared;
2+
using MemoryPack;
3+
using System.Collections.ObjectModel;
4+
5+
namespace ConnectX.Shared.Messages.Identity;
6+
7+
[MessageDefine]
8+
[MemoryPackable]
9+
public partial class SigninResult(
10+
bool succeeded,
11+
Guid userId,
12+
string? errorMessage = null,
13+
IReadOnlyDictionary<string, string>? metadata = null)
14+
{
15+
public const string ErrorProtocolMismatch = "Protocol mismatch";
16+
17+
public const string MetadataServerProtocolMajor = "ServerProtocolMajor";
18+
public const string MetadataServerProtocolMinor = "ServerProtocolMinor";
19+
20+
public bool Succeeded { get; } = succeeded;
21+
public Guid UserId { get; } = userId;
22+
public string? ErrorMessage { get; } = errorMessage;
23+
public IReadOnlyDictionary<string, string> Metadata { get; } = metadata ?? ReadOnlyDictionary<string, string>.Empty;
24+
}

0 commit comments

Comments
 (0)