예제 #1
0
        public async Task <ServerHelloRequest> ClientHelloWithCookie(MasterServerSession session, ClientHelloWithCookieRequest request)
        {
            _logger.Verbose(
                $"Handling {nameof(ClientHelloWithCookieRequest)} " +
                $"(CertificateResponseId={request.CertificateResponseId}, " +
                $"Random='{BitConverter.ToString(request.Random)}', " +
                $"Cookie='{BitConverter.ToString(request.Cookie)}')."
                );
            if (!request.Cookie.SequenceEqual(session.Cookie))
            {
                _logger.Warning(
                    $"Session sent {nameof(ClientHelloWithCookieRequest)} with a mismatching cookie " +
                    $"(EndPoint='{session.EndPoint}', " +
                    $"Cookie='{BitConverter.ToString(request.Cookie)}', " +
                    $"Expected='{BitConverter.ToString(session.Cookie ?? new byte[0])}')."
                    );
                return(null);
            }
            if (!request.Random.SequenceEqual(session.ClientRandom))
            {
                _logger.Warning(
                    $"Session sent {nameof(ClientHelloWithCookieRequest)} with a mismatching client random " +
                    $"(EndPoint='{session.EndPoint}', " +
                    $"Random='{BitConverter.ToString(request.Random)}', " +
                    $"Expected='{BitConverter.ToString(session.ClientRandom ?? new byte[0])}')."
                    );
                return(null);
            }

            // Generate a server random
            session.ServerRandom = _randomProvider.GetRandom();

            // Generate a key pair
            var keyPair = _diffieHellmanService.GetECKeyPair();

            session.ServerPrivateKeyParameters = keyPair.PrivateKeyParameters;

            // Generate a signature
            var signature = MakeSignature(session.ClientRandom, session.ServerRandom, keyPair.PublicKey);

            await _messageDispatcher.SendWithRetry(session, new ServerCertificateRequest()
            {
                ResponseId   = request.CertificateResponseId,
                Certificates = new List <byte[]>()
                {
                    _certificate.RawData
                }
            });

            return(new ServerHelloRequest
            {
                Random = session.ServerRandom,
                PublicKey = keyPair.PublicKey,
                Signature = signature
            });
        }
예제 #2
0
        public async Task <ConnectToServerResponse> ConnectToServer(MasterServerSession session, ConnectToServerRequest request)
        {
            _logger.Verbose(
                $"Handling {nameof(ConnectToServerRequest)} " +
                $"(UserId='{request.UserId}', " +
                $"UserName='******', " +
                $"Random='{BitConverter.ToString(request.Random)}', " +
                $"PublicKey='{BitConverter.ToString(request.PublicKey)}', " +
                $"Secret='{request.Secret}', " +
                $"Code='{request.Code}', " +
                $"Password='******', " +
                $"UseRelay={request.UseRelay})."
                );

            Server server = null;

            if (!String.IsNullOrEmpty(request.Code))
            {
                server = await _serverRepository.GetServerByCode(request.Code);
            }
            else if (!String.IsNullOrEmpty(request.Secret))
            {
                server = await _serverRepository.GetServer(request.Secret);
            }

            if (server is null)
            {
                return new ConnectToServerResponse
                       {
                           Result = ConnectToServerResponse.ResultCode.InvalidCode
                       }
            }
            ;

            if (server.CurrentPlayerCount >= server.MaximumPlayerCount)
            {
                return new ConnectToServerResponse
                       {
                           Result = ConnectToServerResponse.ResultCode.ServerAtCapacity
                       }
            }
            ;

            if (!_sessionService.TryGetSession(server.RemoteEndPoint, out var hostSession))
            {
                _logger.Warning(
                    "Failed to retrieve server host session while handling " +
                    $"{nameof(ConnectToServerRequest)} " +
                    $"(RemoteEndPoint='{server.RemoteEndPoint}', " +
                    $"UserId='{request.UserId}', " +
                    $"UserName='******', " +
                    $"Random='{BitConverter.ToString(request.Random)}', " +
                    $"PublicKey='{BitConverter.ToString(request.PublicKey)}', " +
                    $"Secret='{request.Secret}', " +
                    $"Code='{request.Code}', " +
                    $"Password='******', " +
                    $"UseRelay={request.UseRelay})."
                    );

                return(new ConnectToServerResponse
                {
                    Result = ConnectToServerResponse.ResultCode.UnknownError
                });
            }

            var connectingEndPoint = (IPEndPoint)session.EndPoint;
            var remoteEndPoint     = (IPEndPoint)hostSession.EndPoint;

            if (request.UseRelay)
            {
                GetAvailableRelayServerResponse getAvailableRelayServerResponse;
                try
                {
                    getAvailableRelayServerResponse = await _relayServerService.GetAvailableRelayServer(
                        new GetAvailableRelayServerRequest(
                            session.EndPoint.ToString() !,
                            hostSession.EndPoint.ToString() !
                            )
                        );
                }
                catch (TimeoutException e)
                {
                    _logger.Error(e,
                                  "Failed to get an available relay server while handling " +
                                  $"{nameof(ConnectToServerRequest)} " +
                                  $"(RemoteEndPoint='{server.RemoteEndPoint}', " +
                                  $"UserId='{request.UserId}', " +
                                  $"UserName='******', " +
                                  $"Random='{BitConverter.ToString(request.Random)}', " +
                                  $"PublicKey='{BitConverter.ToString(request.PublicKey)}', " +
                                  $"Secret='{request.Secret}', " +
                                  $"Code='{request.Code}', " +
                                  $"Password='******', " +
                                  $"UseRelay={request.UseRelay})."
                                  );
                    return(new ConnectToServerResponse
                    {
                        Result = ConnectToServerResponse.ResultCode.NoAvailableDedicatedServers
                    });
                }
                if (!getAvailableRelayServerResponse.Success)
                {
                    _logger.Warning(
                        "No available relay servers while handling " +
                        $"{nameof(ConnectToServerRequest)} " +
                        $"(RemoteEndPoint='{server.RemoteEndPoint}', " +
                        $"UserId='{request.UserId}', " +
                        $"UserName='******', " +
                        $"Random='{BitConverter.ToString(request.Random)}', " +
                        $"PublicKey='{BitConverter.ToString(request.PublicKey)}', " +
                        $"Secret='{request.Secret}', " +
                        $"Code='{request.Code}', " +
                        $"Password='******', " +
                        $"UseRelay={request.UseRelay})."
                        );
                    return(new ConnectToServerResponse
                    {
                        Result = ConnectToServerResponse.ResultCode.NoAvailableDedicatedServers
                    });
                }
                remoteEndPoint     = IPEndPoint.Parse(getAvailableRelayServerResponse.RemoteEndPoint);
                connectingEndPoint = remoteEndPoint;
            }

            // Let the host know that someone is about to connect (hole-punch)
            await _messageDispatcher.SendWithRetry(hostSession, new PrepareForConnectionRequest
            {
                UserId            = request.UserId,
                UserName          = request.UserName,
                RemoteEndPoint    = connectingEndPoint,
                Random            = request.Random,
                PublicKey         = request.PublicKey,
                IsConnectionOwner = false,
                IsDedicatedServer = false
            });

            session.Secret = request.Secret;

            _logger.Information(
                "Successfully connected to server " +
                $"(RemoteEndPoint='{remoteEndPoint}', " +
                $"UserId='{request.UserId}', " +
                $"UserName='******', " +
                $"Random='{BitConverter.ToString(request.Random)}', " +
                $"PublicKey='{BitConverter.ToString(request.PublicKey)}', " +
                $"Secret='{request.Secret}', " +
                $"Code='{request.Code}', " +
                $"Password='******', " +
                $"UseRelay={request.UseRelay})."
                );
            return(new ConnectToServerResponse
            {
                Result = ConnectToServerResponse.ResultCode.Success,
                UserId = server.Host.UserId,
                UserName = server.Host.UserName,
                Secret = server.Secret,
                DiscoveryPolicy = (DiscoveryPolicy)server.DiscoveryPolicy,
                InvitePolicy = (InvitePolicy)server.InvitePolicy,
                MaximumPlayerCount = server.MaximumPlayerCount,
                Configuration = new GameplayServerConfiguration()
                {
                    BeatmapDifficultyMask = (BeatmapDifficultyMask)server.BeatmapDifficultyMask,
                    GameplayModifiersMask = (GameplayModifiersMask)server.GameplayModifiersMask,
                    SongPackBloomFilterTop = server.SongPackBloomFilterTop,
                    SongPackBloomFilterBottom = server.SongPackBloomFilterBottom
                },
                IsConnectionOwner = true,
                IsDedicatedServer = false,
                RemoteEndPoint = remoteEndPoint,
                Random = server.Random,
                PublicKey = server.PublicKey
            });
        }