private async Task ManualStartClientConnectionLoop(TcpClient client, IManagedNetworkClient <TPayloadReadType, TPayloadWriteType> internalNetworkClient, ManagedClientSession <TPayloadReadType, TPayloadWriteType> networkSession) { //So that sessions invoking the disconnection can internally disconnect to networkSession.OnSessionDisconnection += (source, args) => internalNetworkClient.Disconnect(); //TODO: Better way to syncronize the strategies used? var dispatchingStrategy = new InPlaceAsyncLockedNetworkMessageDispatchingStrategy <TPayloadReadType, TPayloadWriteType>(); while (client.Connected && internalNetworkClient.isConnected) { NetworkIncomingMessage <TPayloadWriteType> message = await internalNetworkClient.ReadMessageAsync(CancellationToken.None) .ConfigureAwait(false); //We don't want to stop the client just because an exception occurred. try { //TODO: This will work for World of Warcraft since it requires no more than one packet //from the same client be handled at one time. However it limits throughput and maybe we should //handle this at a different level instead. await dispatchingStrategy.DispatchNetworkMessage(new SessionMessageContext <TPayloadReadType, TPayloadWriteType>(networkSession, message)) .ConfigureAwait(false); } catch (Exception e) { //TODO: Remove this console log Logger.Error($"[Error]: {e.Message}\n\nStack: {e.StackTrace}"); } } client.Dispose(); //TODO: Should we tell the client something when it ends? networkSession.DisconnectClientSession(); }
/// <inheritdoc /> public GenericProxiedMessageContext([NotNull] IManagedNetworkClient <TPayloadReadType, TPayloadWriteType> proxyConnection, [NotNull] IConnectionService connectionService, [NotNull] IPeerPayloadSendService <TPayloadWriteType> payloadSendService, [NotNull] IPeerRequestSendService <TPayloadWriteType> requestSendService) { ProxyConnection = proxyConnection ?? throw new ArgumentNullException(nameof(proxyConnection)); ConnectionService = connectionService ?? throw new ArgumentNullException(nameof(connectionService)); PayloadSendService = payloadSendService ?? throw new ArgumentNullException(nameof(payloadSendService)); RequestSendService = requestSendService ?? throw new ArgumentNullException(nameof(requestSendService)); }
/// <summary> /// Starts dispatching the messages and won't yield until /// the client has stopped or has disconnected. /// </summary> /// <returns></returns> protected async Task StartDispatchingAsync([NotNull] IManagedNetworkClient <TOutgoingPayloadType, TIncomingPayloadType> client) { if (client == null) { throw new ArgumentNullException(nameof(client)); } try { IPeerRequestSendService <TOutgoingPayloadType> requestService = new PayloadInterceptMessageSendService <TOutgoingPayloadType>(client, client); if (!client.isConnected && Logger.IsWarnEnabled) { Logger.Warn($"The client was not connected before dispatching started."); } //TODO: Read the next message before awaiting the result of the dispatch message handling. while (client.isConnected && !CancelTokenSource.IsCancellationRequested) //if we exported we should reading messages { NetworkIncomingMessage <TIncomingPayloadType> message = await client.ReadMessageAsync(CancelTokenSource.Token) .ConfigureAwaitFalse(); //Supress and continue reading try { //We don't do anything with the result. We should hope someone registered //a default handler to deal with this situation bool result = await Handlers.TryHandleMessage(MessageContextFactory.Create(client, client, requestService), message) .ConfigureAwaitFalse(); } catch (Exception e) { if (Logger.IsInfoEnabled) { Logger.Info($"Error: {e.Message}\n\n Stack Trace: {e.StackTrace}"); } } } } catch (Exception e) { if (Logger.IsInfoEnabled) { Logger.Info($"Error: {e.Message}\n\n Stack Trace: {e.StackTrace}"); } throw; } finally { if (Logger.IsInfoEnabled) { Logger.Info("Network client stopped reading."); } OnClientStoppedHandlingMessages(); } }
/// <inheritdoc /> public OnStartRestartNetworkClientHandlingInititablize( [NotNull] IManagedNetworkClient <GameClientPacketPayload, GameServerPacketPayload> client, [NotNull] INetworkClientManager clientManager, [NotNull] ILog logger) { Client = client ?? throw new ArgumentNullException(nameof(client)); ClientManager = clientManager ?? throw new ArgumentNullException(nameof(clientManager)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); }
/// <inheritdoc /> public Task StartHandlingNetworkClient(IManagedNetworkClient <TOutgoingPayloadType, TIncomingPayloadType> client) { //Don't await because we want start to end. Task.Factory.StartNew(async() => await StartDispatchingAsync(client).ConfigureAwait(false), CancelTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default) .ConfigureAwait(false); //We don't want to await it, it needs to run at the same time return(Task.CompletedTask); }
public ConnectionCheckDebugTickable(INetworkClientDisconnectedEventSubscribable subService, [NotNull] IManagedNetworkClient <GameClientPacketPayload, GameServerPacketPayload> client, [NotNull] ILog logger, [NotNull] INetworkClientManager clientManager) : base(subService) { Client = client ?? throw new ArgumentNullException(nameof(client)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); ClientManager = clientManager ?? throw new ArgumentNullException(nameof(clientManager)); }
/// <inheritdoc /> public PreBurstStartInstanceClientConnection([NotNull] IManagedNetworkClient <GameClientPacketPayload, GameServerPacketPayload> client, [NotNull] ICharacterService characterDataService, [NotNull] IReadonlyAuthTokenRepository authTokenRepo, [NotNull] ICharacterDataRepository characterDataRepo, [NotNull] IZoneServerService zoneService, [NotNull] ILog logger, [NotNull] INetworkClientManager networkClientManager) { Client = client ?? throw new ArgumentNullException(nameof(client)); CharacterDataService = characterDataService ?? throw new ArgumentNullException(nameof(characterDataService)); AuthTokenRepo = authTokenRepo ?? throw new ArgumentNullException(nameof(authTokenRepo)); CharacterDataRepo = characterDataRepo ?? throw new ArgumentNullException(nameof(characterDataRepo)); ZoneService = zoneService ?? throw new ArgumentNullException(nameof(zoneService)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); NetworkClientManager = networkClientManager ?? throw new ArgumentNullException(nameof(networkClientManager)); }
/// <inheritdoc /> public Task StartHandlingNetworkClient(IManagedNetworkClient <TOutgoingPayloadType, TIncomingPayloadType> client) { isNetworkHandling = true; //Don't await because we want start to end. Task.Factory.StartNew(async() => await StartDispatchingAsync(client).ConfigureAwaitFalseVoid(), TaskCreationOptions.LongRunning) .ConfigureAwaitFalse(); //We don't want to await it, it needs to run at the same time return(Task.CompletedTask); }
private static async Task AsyncMain(IManagedNetworkClient <AuthenticationClientPayload, AuthenticationServerPayload> client) { try { if (!await client.ConnectAsync("127.0.0.1", 5050).ConfigureAwait(false)) { Console.WriteLine("Failed to connect"); } AuthChallengeData challenge = new AuthChallengeData(ProtocolVersion.ProtocolVersionTwo, GameType.WoW, ExpansionType.WrathOfTheLichKing, 3, 5, ClientBuild.Wotlk_3_3_5a, PlatformType.x86, OperatingSystemType.Win, LocaleType.enUS, IPAddress.Parse("127.0.0.1"), "Glader"); await client.SendMessage(new AuthLogonChallengeRequest(challenge)) .ConfigureAwait(false); } catch (Exception e) { Console.WriteLine($"Error: {e.Message}"); } while (true) { var response = (await client.ReadMessageAsync()).Payload; Console.WriteLine("Recieved payload"); AuthenticationLogonChallengeResponseMessageHandler handler = new AuthenticationLogonChallengeResponseMessageHandler(); AuthenticationLogonProofResponseMessageHandler proofHandler = new AuthenticationLogonProofResponseMessageHandler(); RealmListResponseMessageHandler realmListResponseHandler = new RealmListResponseMessageHandler(bytes => Serializer.Deserialize <RealmListContainer>(bytes)); if (response is AuthLogonChallengeResponse challengeResponse) { Console.WriteLine($"Response: Valid: {challengeResponse.isValid} Result: {challengeResponse.Result} SRP: {challengeResponse.Challenge}"); await handler.HandleMessage(new DefaultPeerMessageContext <AuthenticationClientPayload>(client, client, new PayloadInterceptMessageSendService <AuthenticationClientPayload>(client, client)), challengeResponse); } else if (response is AuthRealmListResponse realmListResponse) { await realmListResponseHandler.HandleMessage(new DefaultPeerMessageContext <AuthenticationClientPayload>(client, client, new PayloadInterceptMessageSendService <AuthenticationClientPayload>(client, client)), realmListResponse); } else if (response is AuthLogonProofResponse proofResponse) { await proofHandler.HandleMessage(new DefaultPeerMessageContext <AuthenticationClientPayload>(client, client, new PayloadInterceptMessageSendService <AuthenticationClientPayload>(client, client)), proofResponse); } } }
private static async Task HandlePayload(SharedLoginResponsePayload payload, IManagedNetworkClient <PSOBBGamePacketPayloadClient, PSOBBGamePacketPayloadServer> client) { Console.WriteLine($"Login Response: {payload.ResponseCode}"); if (hasSecurityData && hasAskedForChars && !hasSelectedCharacter) { hasSelectedCharacter = true; await client.SendMessage(new CharacterCharacterSelectionRequestPayload(0, CharacterSelectionType.PlaySelection)); Task.Factory.StartNew(async() => { await Task.Delay(3000); DecryptionKeyInitializer.Uninitialize(); EncryptionKeyInitializer.Uninitialize(); await client.ConnectAsync("158.69.215.131", 12001); }); return; } if (hasSecurityData && !hasAskedForChars) { hasAskedForChars = true; for (int i = 0; i < 4; i++) { await client.SendMessage(new CharacterCharacterSelectionRequestPayload((byte)i, CharacterSelectionType.Preview)); } Task.Factory.StartNew(async() => { await Task.Delay(6000); await client.ConnectAsync("158.69.215.131", 12001); DecryptionKeyInitializer.Uninitialize(); EncryptionKeyInitializer.Uninitialize(); }); } //We should recieve a 19 redirect after this //We should use the bytes from the response for future sessions ClientVerification = new ClientVerificationData(0x41, payload.SecurityData); //.Take(32).Reverse().Concat(payload.SecurityData.Skip(32)).ToArray()); hasSecurityData = true; teamId = payload.TeamId; Console.WriteLine($"Set 32bit key: {payload.TeamId}"); }
private static async Task HandlePayload(SharedWelcomePayload payload, IManagedNetworkClient <PSOBBGamePacketPayloadClient, PSOBBGamePacketPayloadServer> client) { Console.WriteLine($"Server Vector: {payload.ServerVector.Aggregate("", (s, b) => $"{s} {b.ToString()}")}"); Console.WriteLine($"Client Vector: {payload.ClientVector.Aggregate("", (s, b) => $"{s} {b.ToString()}")}"); EncryptionKeyInitializer.Initialize(payload.ClientVector); DecryptionKeyInitializer.Initialize(payload.ServerVector); Console.WriteLine(payload.CopyrightMessage); if (hasSecurityData) { await client.SendMessage(new SharedLoginRequest93Payload(0x41, teamId, "glader", "playpso69", ClientVerification)); } else { await client.SendMessage(new SharedLoginRequest93Payload(0x41, "glader", "playpso69", ClientVerificationData.FromVersionString("TethVer12510"))); } }
public static async Task RunClientAsync(IManagedNetworkClient <PSOBBGamePacketPayloadClient, PSOBBGamePacketPayloadServer> client, string ip, int port) { await client.ConnectAsync(ip, port); while (true) { NetworkIncomingMessage <PSOBBGamePacketPayloadServer> message = await client.ReadMessageAsync(); LogMessage(message); try { await HandlePayload((dynamic)message.Payload, client); } catch (Exception e) { Console.WriteLine(e); throw; } } }
/// <inheritdoc /> protected override void Load(ContainerBuilder builder) { builder.Register(context => LogLevel.All) .As <LogLevel>() .SingleInstance(); builder.RegisterType <UnityLogger>() .As <ILog>() .SingleInstance(); ProtobufNetGladNetSerializerAdapter serializer = new ProtobufNetGladNetSerializerAdapter(PrefixStyle.Fixed32); //The idea here is if the global network client it's null we should use it as the instance. if (GloballyManagedClient == null || !GloballyManagedClient.isConnected) { GloballyManagedClient = new DotNetTcpClientNetworkClient() .AddHeaderlessNetworkMessageReading(serializer) .For <GameServerPacketPayload, GameClientPacketPayload, IPacketPayload>() .Build() .AsManaged(new UnityLogger(LogLevel.All)); //TODO: How should we handle log level? } builder.RegisterInstance(GloballyManagedClient) .As <IManagedNetworkClient <GameClientPacketPayload, GameServerPacketPayload> >() .As <IPeerPayloadSendService <GameClientPacketPayload> >() .As <IPayloadInterceptable>() .As <IConnectionService>(); builder.RegisterType <DefaultMessageContextFactory>() .As <IPeerMessageContextFactory>() .SingleInstance(); builder.RegisterType <PayloadInterceptMessageSendService <GameClientPacketPayload> >() .As <IPeerRequestSendService <GameClientPacketPayload> >() .SingleInstance(); //Now, with the new design we also have to register the game client itself builder.RegisterType <GameNetworkClient>() .AsImplementedInterfaces() .SingleInstance(); }
/// <inheritdoc /> protected override void Load(ContainerBuilder builder) { builder.Register(context => LogLevel.All) .As <LogLevel>() .SingleInstance(); builder.Register <IManagedNetworkClient <GameClientPacketPayload, GameServerPacketPayload> >(context => { //The idea here is if the global network client it's null we should use it as the instance. if (GloballyManagedClient == null || !GloballyManagedClient.isConnected) { return(GloballyManagedClient = new GladMMOUnmanagedNetworkClient <DotNetTcpClientNetworkClient, GameServerPacketPayload, GameClientPacketPayload, IGamePacketPayload>(new DotNetTcpClientNetworkClient(), context.Resolve <INetworkSerializationService>(), context.Resolve <ILog>()) .AsManaged()); } else { return(GloballyManagedClient); } }) .As <IManagedNetworkClient <GameClientPacketPayload, GameServerPacketPayload> >() .As <IPeerPayloadSendService <GameClientPacketPayload> >() .As <IPayloadInterceptable>() .As <IConnectionService>() .SingleInstance(); builder.RegisterType <DefaultMessageContextFactory>() .As <IPeerMessageContextFactory>() .SingleInstance(); builder.RegisterType <PayloadInterceptMessageSendService <GameClientPacketPayload> >() .As <IPeerRequestSendService <GameClientPacketPayload> >() .SingleInstance(); //Now, with the new design we also have to register the game client itself builder.RegisterType <GameNetworkClient>() .AsImplementedInterfaces() .SingleInstance(); }
public async Task StartHandlingNetworkClient(IManagedNetworkClient <GameClientPacketPayload, GameServerPacketPayload> client) { isNetworkHandling = true; }
/// <inheritdoc /> protected override IManagedNetworkClient <PSOBBGamePacketPayloadClient, PSOBBGamePacketPayloadServer> BuildOutgoingSessionManagedClient(NetworkClientBase clientBase, INetworkSerializationService serializeService) { //Copied from the test client project IManagedNetworkClient <PSOBBGamePacketPayloadClient, PSOBBGamePacketPayloadServer> client = clientBase .AddCryptHandling(ServerEncryptionService, ServerDecryptionService) .AddBufferredWrite(4) .AddHeaderReading <PSOBBPacketHeader>(serializeService, 2) .AddNetworkMessageReading(serializeService) .For <PSOBBGamePacketPayloadServer, PSOBBGamePacketPayloadClient, IPacketPayload>(new PSOBBPacketHeaderFactory()) .AddReadBufferClearing() .Build() .AsManagedSession(); return(client); }
private GenericProxiedManagedClientSession <TWriteType, TReadType> BuildSessionFromDependencies <TWriteType, TReadType>(IManagedNetworkClient <TWriteType, TReadType> client, SessionDetails details, IManagedNetworkClient <TReadType, TWriteType> proxyClient) where TReadType : class where TWriteType : class { GenericProxiedManagedClientSession <TWriteType, TReadType> connectionSession; using (ILifetimeScope lifetimeScope = this.ServiceContainer.BeginLifetimeScope(c => { c.RegisterInstance(client) .AsImplementedInterfaces() .AsSelf(); c.RegisterInstance(details) .As <SessionDetails>(); c.RegisterInstance(new GenericMessageContextFactory <TWriteType, TReadType>(proxyClient)) .AsSelf() .AsImplementedInterfaces(); })) { connectionSession = GenerateClientFromLifetimeScope <TWriteType, TReadType>(lifetimeScope); } return(connectionSession); }
private static async Task HandlePayload(object payload, IManagedNetworkClient <PSOBBGamePacketPayloadClient, PSOBBGamePacketPayloadServer> client) { }
private static async Task HandlePayload(SharedConnectionRedirectPayload payload, IManagedNetworkClient <PSOBBGamePacketPayloadClient, PSOBBGamePacketPayloadServer> client) { Console.WriteLine($"Redirect: {payload.EndpointAddress}:{payload.EndpointerPort}"); EncryptionKeyInitializer.Uninitialize(); DecryptionKeyInitializer.Uninitialize(); //Redirects to character the first time await client.ConnectAsync(payload.EndpointAddress, payload.EndpointerPort); }
private static async Task HandlePayload(SharedCreateMessageBoxEventPayload payload, IManagedNetworkClient <PSOBBGamePacketPayloadClient, PSOBBGamePacketPayloadServer> client) { Console.WriteLine($"MessageBox Message: {payload.Message}"); //We should recieve a 19 redirect after this }
private static async Task HandlePayload(CharacterCharacterUpdateResponsePayload payload, IManagedNetworkClient <PSOBBGamePacketPayloadClient, PSOBBGamePacketPayloadServer> client) { Console.WriteLine($"Character: {payload.CharacterData.CharacterName} Class: {payload.CharacterData.ClassRace} SecId: {payload.CharacterData.SectionId} Level: {payload.CharacterData.Progress.Level} PlayedTime: {payload.CharacterData.PlayedTime}"); Console.WriteLine($"Character: {Encoding.Unicode.GetBytes(payload.CharacterData.CharacterName).Aggregate("", (s, b) => $"{s} {b}")}"); //Console.WriteLine($"Leftover Bytes: {payload.CharacterData.LeftoverBytes.Aggregate("", (s, b) => $"{s} {b}")}"); }
public GenericMessageContextFactory([NotNull] IManagedNetworkClient <TPayloadReadType, TPayloadWriteType> proxyConnection) { ProxyConnection = proxyConnection ?? throw new ArgumentNullException(nameof(proxyConnection)); }